Skip to content

Commit 02740b4

Browse files
hyperpolymathclaude
andcommitted
feat: add lang-mcp cartridge for nextgen-languages
New cartridge supporting all 12 hyperpolymath nextgen-languages: Eclexia, AffineScript, BetLang, Ephapax, MyLang, WokeLang, Anvomidav, Phronesis, Error-lang, Julia-the-Viper, Me-dialect, Oblibeny. Architecture: session-based state machine (idle → compiling → checked → evaluating → idle/error) with 8 concurrent sessions, URL-based language service dispatch, type-checking and evaluation endpoints. Zig FFI: 6 exported functions + 6 tests. V-lang adapter: full CRUD + typecheck + eval. MCP bridge updated with lang-mcp in Teranga menu. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2d8a720 commit 02740b4

3 files changed

Lines changed: 587 additions & 0 deletions

File tree

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
// SPDX-License-Identifier: PMPL-1.0-or-later
2+
// Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
//
4+
// Lang-MCP Cartridge — V-lang adapter layer.
5+
//
6+
// Bridges the Zig FFI (lang_ffi.zig) to REST/gRPC/GraphQL endpoints.
7+
// Provides language session management, type-checking, and evaluation
8+
// for the hyperpolymath nextgen-languages family.
9+
10+
module lang_adapter
11+
12+
import json
13+
14+
// ═══════════════════════════════════════════════════════════════════════
15+
// C FFI declarations (link against lang_ffi built from Zig)
16+
// ═══════════════════════════════════════════════════════════════════════
17+
18+
fn C.lang_session_start(lang_id int, name_ptr &u8, name_len usize) int
19+
fn C.lang_session_set_url(sess_idx int, url_ptr &u8, url_len usize) int
20+
fn C.lang_session_end(sess_idx int) int
21+
fn C.lang_session_state(sess_idx int) int
22+
fn C.lang_session_language(sess_idx int) int
23+
fn C.lang_typecheck(sess_idx int, src_ptr &u8, src_len usize, out_ptr &u8, out_len usize) int
24+
fn C.lang_eval(sess_idx int, src_ptr &u8, src_len usize, out_ptr &u8, out_len usize) int
25+
fn C.lang_reset()
26+
27+
// ═══════════════════════════════════════════════════════════════════════
28+
// Types
29+
// ═══════════════════════════════════════════════════════════════════════
30+
31+
enum LangState {
32+
idle = 0
33+
compiling = 1
34+
checked = 2
35+
evaluating = 3
36+
err = 4
37+
}
38+
39+
enum Language {
40+
eclexia = 1
41+
affinescript = 2
42+
betlang = 3
43+
ephapax = 4
44+
mylang = 5
45+
wokelang = 6
46+
anvomidav = 7
47+
phronesis = 8
48+
error_lang = 9
49+
julia_the_viper = 10
50+
me_dialect = 11
51+
oblibeny = 12
52+
custom = 99
53+
}
54+
55+
fn state_label(s int) string {
56+
return match s {
57+
0 { 'idle' }
58+
1 { 'compiling' }
59+
2 { 'checked' }
60+
3 { 'evaluating' }
61+
4 { 'error' }
62+
else { 'unknown' }
63+
}
64+
}
65+
66+
fn language_label(lang string) !int {
67+
return match lang {
68+
'eclexia' { 1 }
69+
'affinescript' { 2 }
70+
'betlang' { 3 }
71+
'ephapax' { 4 }
72+
'mylang' { 5 }
73+
'wokelang' { 6 }
74+
'anvomidav' { 7 }
75+
'phronesis' { 8 }
76+
'error-lang' { 9 }
77+
'julia-the-viper' { 10 }
78+
'me-dialect' { 11 }
79+
'oblibeny' { 12 }
80+
else { return error('unknown language: ${lang}') }
81+
}
82+
}
83+
84+
// ═══════════════════════════════════════════════════════════════════════
85+
// REST API Responses
86+
// ═══════════════════════════════════════════════════════════════════════
87+
88+
struct SessionResponse {
89+
session int
90+
language string
91+
state string
92+
}
93+
94+
// ═══════════════════════════════════════════════════════════════════════
95+
// Adapter Functions (called by main adapter router)
96+
// ═══════════════════════════════════════════════════════════════════════
97+
98+
pub fn start_session(language_name string, session_name string) !SessionResponse {
99+
lang_id := language_label(language_name)!
100+
sess := C.lang_session_start(lang_id, session_name.str, usize(session_name.len))
101+
if sess < 0 {
102+
return match sess {
103+
-1 { error('no session slots available (max 8)') }
104+
-2 { error('invalid session name') }
105+
else { error('unknown error (code ${sess})') }
106+
}
107+
}
108+
return SessionResponse{
109+
session: sess
110+
language: language_name
111+
state: 'idle'
112+
}
113+
}
114+
115+
pub fn set_url(session int, url string) !string {
116+
result := C.lang_session_set_url(session, url.str, usize(url.len))
117+
return match result {
118+
0 { 'URL set for session ${session}' }
119+
-1 { return error('invalid or inactive session') }
120+
-6 { return error('URL empty or too long') }
121+
else { return error('unknown error (code ${result})') }
122+
}
123+
}
124+
125+
pub fn end_session(session int) !string {
126+
result := C.lang_session_end(session)
127+
return match result {
128+
0 { 'session ${session} ended' }
129+
-1 { return error('invalid or inactive session') }
130+
else { return error('unknown error (code ${result})') }
131+
}
132+
}
133+
134+
pub fn get_state(session int) string {
135+
s := C.lang_session_state(session)
136+
return state_label(s)
137+
}
138+
139+
pub fn typecheck(session int, source string) !string {
140+
if session < 0 || session > 7 {
141+
return error('invalid session index: ${session}')
142+
}
143+
mut out_buf := []u8{len: 65536}
144+
result := C.lang_typecheck(session, source.str, usize(source.len), out_buf.data, usize(out_buf.len))
145+
if result < 0 {
146+
return match result {
147+
-1 { error('invalid or inactive session') }
148+
-2 { error('session not in valid state for type-checking') }
149+
-5 { error('output buffer too small') }
150+
-6 { error('no service URL set for this session') }
151+
-7 { error('type-check service call failed') }
152+
else { error('unknown error (code ${result})') }
153+
}
154+
}
155+
return out_buf[..result].bytestr()
156+
}
157+
158+
pub fn evaluate(session int, source string) !string {
159+
if session < 0 || session > 7 {
160+
return error('invalid session index: ${session}')
161+
}
162+
mut out_buf := []u8{len: 65536}
163+
result := C.lang_eval(session, source.str, usize(source.len), out_buf.data, usize(out_buf.len))
164+
if result < 0 {
165+
return match result {
166+
-1 { error('invalid or inactive session') }
167+
-2 { error('session not in valid state for evaluation') }
168+
-5 { error('output buffer too small') }
169+
-6 { error('no service URL set for this session') }
170+
-7 { error('evaluation service call failed') }
171+
else { error('unknown error (code ${result})') }
172+
}
173+
}
174+
return out_buf[..result].bytestr()
175+
}
176+
177+
pub fn list_languages() string {
178+
return '["eclexia","affinescript","betlang","ephapax","mylang","wokelang","anvomidav","phronesis","error-lang","julia-the-viper","me-dialect","oblibeny"]'
179+
}
180+
181+
pub fn reset() {
182+
C.lang_reset()
183+
}

0 commit comments

Comments
 (0)