smokes: add curated LLVM runner; archive legacy smokes; PHI-off unified across Bridge/Builder; LLVM resolver tracing; minimal Throw lowering; config env getters; dev profile and root cleaner; docs updated; CI workflow runs curated LLVM (PHI-on/off)
This commit is contained in:
316
build.rs
316
build.rs
@ -40,7 +40,10 @@ type_rules = [
|
||||
]
|
||||
"#;
|
||||
fs::write(&grammar_file, minimal).expect("write minimal unified-grammar.toml");
|
||||
println!("cargo:warning=Created minimal grammar at {}", grammar_file.display());
|
||||
println!(
|
||||
"cargo:warning=Created minimal grammar at {}",
|
||||
grammar_file.display()
|
||||
);
|
||||
}
|
||||
|
||||
// Read and very light parse: collect
|
||||
@ -69,7 +72,10 @@ type_rules = [
|
||||
for line in content.lines() {
|
||||
let s = line.trim();
|
||||
if s.starts_with("[keywords.") && s.ends_with("]") {
|
||||
let name = s.trim_start_matches("[keywords.").trim_end_matches("]").to_string();
|
||||
let name = s
|
||||
.trim_start_matches("[keywords.")
|
||||
.trim_end_matches("]")
|
||||
.to_string();
|
||||
current_key = Some(name);
|
||||
in_operators_add = false;
|
||||
in_operators_sub = false;
|
||||
@ -77,25 +83,66 @@ type_rules = [
|
||||
in_operators_div = false;
|
||||
continue;
|
||||
}
|
||||
if s == "[operators.add]" { current_key = None; in_operators_add = true; in_operators_sub=false; in_operators_mul=false; in_operators_div=false; in_type_rules = false; continue; }
|
||||
if s == "[operators.sub]" { current_key = None; in_operators_add = false; in_operators_sub=true; in_operators_mul=false; in_operators_div=false; in_type_rules = false; continue; }
|
||||
if s == "[operators.mul]" { current_key = None; in_operators_add = false; in_operators_sub=false; in_operators_mul=true; in_operators_div=false; in_type_rules = false; continue; }
|
||||
if s == "[operators.div]" { current_key = None; in_operators_add = false; in_operators_sub=false; in_operators_mul=false; in_operators_div=true; in_type_rules = false; continue; }
|
||||
if s == "[operators.add]" {
|
||||
current_key = None;
|
||||
in_operators_add = true;
|
||||
in_operators_sub = false;
|
||||
in_operators_mul = false;
|
||||
in_operators_div = false;
|
||||
in_type_rules = false;
|
||||
continue;
|
||||
}
|
||||
if s == "[operators.sub]" {
|
||||
current_key = None;
|
||||
in_operators_add = false;
|
||||
in_operators_sub = true;
|
||||
in_operators_mul = false;
|
||||
in_operators_div = false;
|
||||
in_type_rules = false;
|
||||
continue;
|
||||
}
|
||||
if s == "[operators.mul]" {
|
||||
current_key = None;
|
||||
in_operators_add = false;
|
||||
in_operators_sub = false;
|
||||
in_operators_mul = true;
|
||||
in_operators_div = false;
|
||||
in_type_rules = false;
|
||||
continue;
|
||||
}
|
||||
if s == "[operators.div]" {
|
||||
current_key = None;
|
||||
in_operators_add = false;
|
||||
in_operators_sub = false;
|
||||
in_operators_mul = false;
|
||||
in_operators_div = true;
|
||||
in_type_rules = false;
|
||||
continue;
|
||||
}
|
||||
if let Some(ref key) = current_key {
|
||||
if let Some(rest) = s.strip_prefix("token") {
|
||||
if let Some(eq) = rest.find('=') {
|
||||
let val = rest[eq+1..].trim().trim_matches('"').to_string();
|
||||
let val = rest[eq + 1..].trim().trim_matches('"').to_string();
|
||||
entries.push((key.clone(), val));
|
||||
}
|
||||
}
|
||||
}
|
||||
if in_operators_add || in_operators_sub || in_operators_mul || in_operators_div {
|
||||
if s.starts_with("type_rules") && s.contains('[') { in_type_rules = true; continue; }
|
||||
if s.starts_with("type_rules") && s.contains('[') {
|
||||
in_type_rules = true;
|
||||
continue;
|
||||
}
|
||||
if in_type_rules {
|
||||
if s.starts_with(']') { in_type_rules = false; continue; }
|
||||
if s.starts_with(']') {
|
||||
in_type_rules = false;
|
||||
continue;
|
||||
}
|
||||
// Expect lines like: { left = "String", right = "String", result = "String", action = "concat" },
|
||||
if s.starts_with('{') && s.ends_with("},") || s.ends_with('}') {
|
||||
let inner = s.trim_start_matches('{').trim_end_matches('}').trim_end_matches(',');
|
||||
let inner = s
|
||||
.trim_start_matches('{')
|
||||
.trim_end_matches('}')
|
||||
.trim_end_matches(',');
|
||||
let mut left = String::new();
|
||||
let mut right = String::new();
|
||||
let mut result = String::new();
|
||||
@ -104,7 +151,7 @@ type_rules = [
|
||||
let kv = part.trim();
|
||||
if let Some(eq) = kv.find('=') {
|
||||
let key = kv[..eq].trim();
|
||||
let val = kv[eq+1..].trim().trim_matches('"').to_string();
|
||||
let val = kv[eq + 1..].trim().trim_matches('"').to_string();
|
||||
match key {
|
||||
"left" => left = val,
|
||||
"right" => right = val,
|
||||
@ -114,21 +161,35 @@ type_rules = [
|
||||
}
|
||||
}
|
||||
}
|
||||
if !left.is_empty() && !right.is_empty() && !result.is_empty() && !action.is_empty() {
|
||||
if in_operators_add { add_rules.push((left, right, result, action)); }
|
||||
else if in_operators_sub { sub_rules.push((left, right, result, action)); }
|
||||
else if in_operators_mul { mul_rules.push((left, right, result, action)); }
|
||||
else if in_operators_div { div_rules.push((left, right, result, action)); }
|
||||
if !left.is_empty()
|
||||
&& !right.is_empty()
|
||||
&& !result.is_empty()
|
||||
&& !action.is_empty()
|
||||
{
|
||||
if in_operators_add {
|
||||
add_rules.push((left, right, result, action));
|
||||
} else if in_operators_sub {
|
||||
sub_rules.push((left, right, result, action));
|
||||
} else if in_operators_mul {
|
||||
mul_rules.push((left, right, result, action));
|
||||
} else if in_operators_div {
|
||||
div_rules.push((left, right, result, action));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(rest) = s.strip_prefix("coercion_strategy") {
|
||||
if let Some(eq) = rest.find('=') {
|
||||
let val = rest[eq+1..].trim().trim_matches('"').to_string();
|
||||
if in_operators_add { add_coercion = Some(val.clone()); }
|
||||
else if in_operators_sub { sub_coercion = Some(val.clone()); }
|
||||
else if in_operators_mul { mul_coercion = Some(val.clone()); }
|
||||
else if in_operators_div { div_coercion = Some(val.clone()); }
|
||||
let val = rest[eq + 1..].trim().trim_matches('"').to_string();
|
||||
if in_operators_add {
|
||||
add_coercion = Some(val.clone());
|
||||
} else if in_operators_sub {
|
||||
sub_coercion = Some(val.clone());
|
||||
} else if in_operators_mul {
|
||||
mul_coercion = Some(val.clone());
|
||||
} else if in_operators_div {
|
||||
div_coercion = Some(val.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -136,27 +197,102 @@ type_rules = [
|
||||
|
||||
// Default rules if none present in TOML (keep codegen deterministic)
|
||||
if add_rules.is_empty() {
|
||||
add_rules.push(("String".into(), "String".into(), "String".into(), "concat".into()));
|
||||
add_rules.push(("String".into(), "Integer".into(), "String".into(), "concat".into()));
|
||||
add_rules.push(("Integer".into(), "String".into(), "String".into(), "concat".into()));
|
||||
add_rules.push(("String".into(), "Bool".into(), "String".into(), "concat".into()));
|
||||
add_rules.push(("Bool".into(), "String".into(), "String".into(), "concat".into()));
|
||||
add_rules.push(("String".into(), "Other".into(), "String".into(), "concat".into()));
|
||||
add_rules.push(("Other".into(), "String".into(), "String".into(), "concat".into()));
|
||||
add_rules.push(("Integer".into(), "Integer".into(), "Integer".into(), "add_i64".into()));
|
||||
add_rules.push(("Float".into(), "Float".into(), "Float".into(), "add_f64".into()));
|
||||
add_rules.push((
|
||||
"String".into(),
|
||||
"String".into(),
|
||||
"String".into(),
|
||||
"concat".into(),
|
||||
));
|
||||
add_rules.push((
|
||||
"String".into(),
|
||||
"Integer".into(),
|
||||
"String".into(),
|
||||
"concat".into(),
|
||||
));
|
||||
add_rules.push((
|
||||
"Integer".into(),
|
||||
"String".into(),
|
||||
"String".into(),
|
||||
"concat".into(),
|
||||
));
|
||||
add_rules.push((
|
||||
"String".into(),
|
||||
"Bool".into(),
|
||||
"String".into(),
|
||||
"concat".into(),
|
||||
));
|
||||
add_rules.push((
|
||||
"Bool".into(),
|
||||
"String".into(),
|
||||
"String".into(),
|
||||
"concat".into(),
|
||||
));
|
||||
add_rules.push((
|
||||
"String".into(),
|
||||
"Other".into(),
|
||||
"String".into(),
|
||||
"concat".into(),
|
||||
));
|
||||
add_rules.push((
|
||||
"Other".into(),
|
||||
"String".into(),
|
||||
"String".into(),
|
||||
"concat".into(),
|
||||
));
|
||||
add_rules.push((
|
||||
"Integer".into(),
|
||||
"Integer".into(),
|
||||
"Integer".into(),
|
||||
"add_i64".into(),
|
||||
));
|
||||
add_rules.push((
|
||||
"Float".into(),
|
||||
"Float".into(),
|
||||
"Float".into(),
|
||||
"add_f64".into(),
|
||||
));
|
||||
}
|
||||
if sub_rules.is_empty() {
|
||||
sub_rules.push(("Integer".into(), "Integer".into(), "Integer".into(), "sub_i64".into()));
|
||||
sub_rules.push(("Float".into(), "Float".into(), "Float".into(), "sub_f64".into()));
|
||||
sub_rules.push((
|
||||
"Integer".into(),
|
||||
"Integer".into(),
|
||||
"Integer".into(),
|
||||
"sub_i64".into(),
|
||||
));
|
||||
sub_rules.push((
|
||||
"Float".into(),
|
||||
"Float".into(),
|
||||
"Float".into(),
|
||||
"sub_f64".into(),
|
||||
));
|
||||
}
|
||||
if mul_rules.is_empty() {
|
||||
mul_rules.push(("Integer".into(), "Integer".into(), "Integer".into(), "mul_i64".into()));
|
||||
mul_rules.push(("Float".into(), "Float".into(), "Float".into(), "mul_f64".into()));
|
||||
mul_rules.push((
|
||||
"Integer".into(),
|
||||
"Integer".into(),
|
||||
"Integer".into(),
|
||||
"mul_i64".into(),
|
||||
));
|
||||
mul_rules.push((
|
||||
"Float".into(),
|
||||
"Float".into(),
|
||||
"Float".into(),
|
||||
"mul_f64".into(),
|
||||
));
|
||||
}
|
||||
if div_rules.is_empty() {
|
||||
div_rules.push(("Integer".into(), "Integer".into(), "Integer".into(), "div_i64".into()));
|
||||
div_rules.push(("Float".into(), "Float".into(), "Float".into(), "div_f64".into()));
|
||||
div_rules.push((
|
||||
"Integer".into(),
|
||||
"Integer".into(),
|
||||
"Integer".into(),
|
||||
"div_i64".into(),
|
||||
));
|
||||
div_rules.push((
|
||||
"Float".into(),
|
||||
"Float".into(),
|
||||
"Float".into(),
|
||||
"div_f64".into(),
|
||||
));
|
||||
}
|
||||
|
||||
// Generate Rust code
|
||||
@ -171,32 +307,56 @@ type_rules = [
|
||||
let sub_coercion_val = sub_coercion.unwrap_or_else(|| "numeric_only".to_string());
|
||||
let mul_coercion_val = mul_coercion.unwrap_or_else(|| "numeric_only".to_string());
|
||||
let div_coercion_val = div_coercion.unwrap_or_else(|| "numeric_only".to_string());
|
||||
code.push_str(&format!("\npub static OPERATORS_ADD_COERCION: &str = \"{}\";\n", add_coercion_val));
|
||||
code.push_str(&format!("pub static OPERATORS_SUB_COERCION: &str = \"{}\";\n", sub_coercion_val));
|
||||
code.push_str(&format!("pub static OPERATORS_MUL_COERCION: &str = \"{}\";\n", mul_coercion_val));
|
||||
code.push_str(&format!("pub static OPERATORS_DIV_COERCION: &str = \"{}\";\n", div_coercion_val));
|
||||
code.push_str(&format!(
|
||||
"\npub static OPERATORS_ADD_COERCION: &str = \"{}\";\n",
|
||||
add_coercion_val
|
||||
));
|
||||
code.push_str(&format!(
|
||||
"pub static OPERATORS_SUB_COERCION: &str = \"{}\";\n",
|
||||
sub_coercion_val
|
||||
));
|
||||
code.push_str(&format!(
|
||||
"pub static OPERATORS_MUL_COERCION: &str = \"{}\";\n",
|
||||
mul_coercion_val
|
||||
));
|
||||
code.push_str(&format!(
|
||||
"pub static OPERATORS_DIV_COERCION: &str = \"{}\";\n",
|
||||
div_coercion_val
|
||||
));
|
||||
// Emit add rules
|
||||
code.push_str("pub static OPERATORS_ADD_RULES: &[(&str, &str, &str, &str)] = &[\n");
|
||||
for (l, r, res, act) in &add_rules {
|
||||
code.push_str(&format!(" (\"{}\", \"{}\", \"{}\", \"{}\"),\n", l, r, res, act));
|
||||
code.push_str(&format!(
|
||||
" (\"{}\", \"{}\", \"{}\", \"{}\"),\n",
|
||||
l, r, res, act
|
||||
));
|
||||
}
|
||||
code.push_str("];");
|
||||
// Emit sub rules
|
||||
code.push_str("\npub static OPERATORS_SUB_RULES: &[(&str, &str, &str, &str)] = &[\n");
|
||||
for (l, r, res, act) in &sub_rules {
|
||||
code.push_str(&format!(" (\"{}\", \"{}\", \"{}\", \"{}\"),\n", l, r, res, act));
|
||||
code.push_str(&format!(
|
||||
" (\"{}\", \"{}\", \"{}\", \"{}\"),\n",
|
||||
l, r, res, act
|
||||
));
|
||||
}
|
||||
code.push_str("];");
|
||||
// Emit mul rules
|
||||
code.push_str("\npub static OPERATORS_MUL_RULES: &[(&str, &str, &str, &str)] = &[\n");
|
||||
for (l, r, res, act) in &mul_rules {
|
||||
code.push_str(&format!(" (\"{}\", \"{}\", \"{}\", \"{}\"),\n", l, r, res, act));
|
||||
code.push_str(&format!(
|
||||
" (\"{}\", \"{}\", \"{}\", \"{}\"),\n",
|
||||
l, r, res, act
|
||||
));
|
||||
}
|
||||
code.push_str("];");
|
||||
// Emit div rules
|
||||
code.push_str("\npub static OPERATORS_DIV_RULES: &[(&str, &str, &str, &str)] = &[\n");
|
||||
for (l, r, res, act) in &div_rules {
|
||||
code.push_str(&format!(" (\"{}\", \"{}\", \"{}\", \"{}\"),\n", l, r, res, act));
|
||||
code.push_str(&format!(
|
||||
" (\"{}\", \"{}\", \"{}\", \"{}\"),\n",
|
||||
l, r, res, act
|
||||
));
|
||||
}
|
||||
code.push_str("];");
|
||||
code.push_str(
|
||||
@ -207,7 +367,8 @@ pub fn lookup_keyword(word: &str) -> Option<&'static str> {
|
||||
}
|
||||
None
|
||||
}
|
||||
"#);
|
||||
"#,
|
||||
);
|
||||
|
||||
// --- Naive parse for syntax rules (statements/expressions) ---
|
||||
let mut syntax_statements: Vec<String> = Vec::new();
|
||||
@ -216,24 +377,43 @@ pub fn lookup_keyword(word: &str) -> Option<&'static str> {
|
||||
let mut in_syntax_expressions = false;
|
||||
for line in content.lines() {
|
||||
let s = line.trim();
|
||||
if s == "[syntax.statements]" { in_syntax_statements = true; in_syntax_expressions = false; continue; }
|
||||
if s == "[syntax.expressions]" { in_syntax_statements = false; in_syntax_expressions = true; continue; }
|
||||
if s.starts_with('[') { in_syntax_statements = false; in_syntax_expressions = false; }
|
||||
if s == "[syntax.statements]" {
|
||||
in_syntax_statements = true;
|
||||
in_syntax_expressions = false;
|
||||
continue;
|
||||
}
|
||||
if s == "[syntax.expressions]" {
|
||||
in_syntax_statements = false;
|
||||
in_syntax_expressions = true;
|
||||
continue;
|
||||
}
|
||||
if s.starts_with('[') {
|
||||
in_syntax_statements = false;
|
||||
in_syntax_expressions = false;
|
||||
}
|
||||
if in_syntax_statements {
|
||||
if let Some(rest) = s.strip_prefix("allow") {
|
||||
if let Some(eq) = rest.find('=') { let arr = rest[eq+1..].trim();
|
||||
if let Some(eq) = rest.find('=') {
|
||||
let arr = rest[eq + 1..].trim();
|
||||
// Expect [ "if", "loop", ... ] possibly spanning multiple lines; simple split for this snapshot
|
||||
for part in arr.trim_matches(&['[',']'][..]).split(',') {
|
||||
let v = part.trim().trim_matches('"'); if !v.is_empty() { syntax_statements.push(v.to_string()); }
|
||||
for part in arr.trim_matches(&['[', ']'][..]).split(',') {
|
||||
let v = part.trim().trim_matches('"');
|
||||
if !v.is_empty() {
|
||||
syntax_statements.push(v.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if in_syntax_expressions {
|
||||
if let Some(rest) = s.strip_prefix("allow_binops") {
|
||||
if let Some(eq) = rest.find('=') { let arr = rest[eq+1..].trim();
|
||||
for part in arr.trim_matches(&['[',']'][..]).split(',') {
|
||||
let v = part.trim().trim_matches('"'); if !v.is_empty() { syntax_binops.push(v.to_string()); }
|
||||
if let Some(eq) = rest.find('=') {
|
||||
let arr = rest[eq + 1..].trim();
|
||||
for part in arr.trim_matches(&['[', ']'][..]).split(',') {
|
||||
let v = part.trim().trim_matches('"');
|
||||
if !v.is_empty() {
|
||||
syntax_binops.push(v.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -241,9 +421,23 @@ pub fn lookup_keyword(word: &str) -> Option<&'static str> {
|
||||
}
|
||||
if syntax_statements.is_empty() {
|
||||
syntax_statements = vec![
|
||||
"box".into(), "global".into(), "function".into(), "static".into(),
|
||||
"if".into(), "loop".into(), "break".into(), "return".into(), "print".into(),
|
||||
"nowait".into(), "include".into(), "local".into(), "outbox".into(), "try".into(), "throw".into(), "using".into(), "from".into()
|
||||
"box".into(),
|
||||
"global".into(),
|
||||
"function".into(),
|
||||
"static".into(),
|
||||
"if".into(),
|
||||
"loop".into(),
|
||||
"break".into(),
|
||||
"return".into(),
|
||||
"print".into(),
|
||||
"nowait".into(),
|
||||
"include".into(),
|
||||
"local".into(),
|
||||
"outbox".into(),
|
||||
"try".into(),
|
||||
"throw".into(),
|
||||
"using".into(),
|
||||
"from".into(),
|
||||
];
|
||||
}
|
||||
if syntax_binops.is_empty() {
|
||||
@ -251,10 +445,14 @@ pub fn lookup_keyword(word: &str) -> Option<&'static str> {
|
||||
}
|
||||
// Emit syntax arrays
|
||||
code.push_str("\npub static SYNTAX_ALLOWED_STATEMENTS: &[&str] = &[\n");
|
||||
for k in &syntax_statements { code.push_str(&format!(" \"{}\",\n", k)); }
|
||||
for k in &syntax_statements {
|
||||
code.push_str(&format!(" \"{}\",\n", k));
|
||||
}
|
||||
code.push_str("];");
|
||||
code.push_str("\npub static SYNTAX_ALLOWED_BINOPS: &[&str] = &[\n");
|
||||
for k in &syntax_binops { code.push_str(&format!(" \"{}\",\n", k)); }
|
||||
for k in &syntax_binops {
|
||||
code.push_str(&format!(" \"{}\",\n", k));
|
||||
}
|
||||
code.push_str("];");
|
||||
|
||||
fs::write(&out_file, code).expect("write generated.rs");
|
||||
|
||||
Reference in New Issue
Block a user