1
0
Fork 0
mirror of https://github.com/imjasonh/nescript synced 2026-07-10 09:42:37 +00:00

Language: struct literals

struct Vec2 { x: u8, y: u8 }
    var pos: Vec2 = Vec2 { x: 100, y: 50 }
    on frame {
        pos = Vec2 { x: pos.x + 1, y: pos.y }
    }

- AST: new \`Expr::StructLiteral(name, fields, span)\` variant
- Parser: in expression position, \`Ident {\` enters struct-literal
  mode when the new \`restrict_struct_literals\` flag is off.
  \`if\`/\`while\`/\`for\` conditions set the flag so the \`{\` keeps
  going to the following block. Condition contexts can still use
  struct literals by parenthesizing them.
- Analyzer: validates that the struct type exists, each named field
  belongs to it, and each field value has a compatible type.
- IR lowering: desugars \`var = StructLiteral { ... }\` (both in
  assignments and variable initializers) into per-field StoreVar
  operations against the analyzer-synthesized \`var.field\`
  variables. No IR type for struct values is needed.
- AST codegen: no-op (legacy path).
- examples/structs_enums_for.ne now uses a struct literal for the
  initial \`player\` state instead of per-field assignments.

https://claude.ai/code/session_01W6eQFStA66EuMKHUFo2rx3
This commit is contained in:
Claude 2026-04-12 17:15:57 +00:00
parent f17f1e7267
commit c8ae433a7c
No known key found for this signature in database
9 changed files with 221 additions and 13 deletions

View file

@ -364,6 +364,34 @@ impl Analyzer {
self.walk_expr_reads(e);
}
}
Expr::StructLiteral(name, fields, span) => {
// Validate that the struct type exists and that each
// named field is actually declared. Missing or extra
// fields are an error; duplicate fields are silently
// ignored (last-writer-wins).
if let Some(layout) = self.struct_layouts.get(name).cloned() {
for (fname, fexpr) in fields {
if let Some((_, field_type, _)) =
layout.fields.iter().find(|(n, _, _)| n == fname)
{
self.walk_expr_reads(fexpr);
self.check_expr_type(fexpr, field_type);
} else {
self.diagnostics.push(Diagnostic::error(
ErrorCode::E0201,
format!("struct '{name}' has no field '{fname}'"),
*span,
));
}
}
} else {
self.diagnostics.push(Diagnostic::error(
ErrorCode::E0201,
format!("unknown struct type '{name}'"),
*span,
));
}
}
Expr::IntLiteral(_, _) | Expr::BoolLiteral(_, _) | Expr::ButtonRead(_, _, _) => {}
}
}
@ -1149,6 +1177,7 @@ impl Analyzer {
}
Expr::ArrayLiteral(_, _) => Some(NesType::U8), // element type inferred from context
Expr::Cast(_, target, _) => Some(target.clone()),
Expr::StructLiteral(name, _, _) => Some(NesType::Struct(name.clone())),
}
}
}
@ -1366,6 +1395,11 @@ fn collect_calls_expr(expr: &Expr, calls: &mut Vec<String>) {
collect_calls_expr(e, calls);
}
}
Expr::StructLiteral(_, fields, _) => {
for (_, e) in fields {
collect_calls_expr(e, calls);
}
}
Expr::Cast(inner, _, _) => {
collect_calls_expr(inner, calls);
}