Skip to main content

normalize_surface_syntax/ir/
mod.rs

1//! Core IR types for surface syntax translation.
2//!
3//! This IR is deliberately minimal and opcode-agnostic. It represents
4//! common programming constructs without domain-specific knowledge.
5//!
6//! Domain operations like `lotus.spawn_entity(x)` are just function calls -
7//! the runtime (spore) provides the actual implementations.
8
9mod expr;
10mod pat;
11mod stmt;
12mod structure_eq;
13
14pub use expr::*;
15pub use pat::*;
16pub use stmt::*;
17pub use structure_eq::StructureEq;
18
19use serde::{Deserialize, Serialize};
20
21/// Source location span (1-based lines, 0-based columns).
22///
23/// Used for error messages ("expected foo at line 5:12") and debugging
24/// round-trips. Writers ignore spans in their output — they are read-only
25/// metadata populated by input readers.
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
27pub struct Span {
28    pub start_line: u32,
29    pub start_col: u32,
30    pub end_line: u32,
31    pub end_col: u32,
32}
33
34impl Span {
35    /// Create a span from tree-sitter `Point` values.
36    ///
37    /// Tree-sitter uses 0-based rows; we expose 1-based lines for
38    /// human-readable error messages.
39    pub fn from_ts(start: tree_sitter::Point, end: tree_sitter::Point) -> Self {
40        Self {
41            start_line: start.row as u32 + 1,
42            start_col: start.column as u32,
43            end_line: end.row as u32 + 1,
44            end_col: end.column as u32,
45        }
46    }
47}
48
49/// A complete program/module.
50#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
51pub struct Program {
52    /// Top-level statements.
53    pub body: Vec<Stmt>,
54}
55
56impl Program {
57    pub fn new(body: Vec<Stmt>) -> Self {
58        Self { body }
59    }
60}
61
62/// A function parameter.
63#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
64pub struct Param {
65    /// Parameter name.
66    pub name: String,
67    /// Optional type annotation (e.g. `string` for `x: string` in TypeScript,
68    /// `str` for `x: str` in Python). Carried as raw source text; not interpreted.
69    #[serde(skip_serializing_if = "Option::is_none")]
70    pub type_annotation: Option<String>,
71}
72
73impl Param {
74    /// Create a plain parameter with no type annotation.
75    pub fn new(name: impl Into<String>) -> Self {
76        Self {
77            name: name.into(),
78            type_annotation: None,
79        }
80    }
81
82    /// Create a typed parameter.
83    pub fn typed(name: impl Into<String>, annotation: impl Into<String>) -> Self {
84        Self {
85            name: name.into(),
86            type_annotation: Some(annotation.into()),
87        }
88    }
89}
90
91impl From<&str> for Param {
92    fn from(s: &str) -> Self {
93        Param::new(s)
94    }
95}
96
97impl From<String> for Param {
98    fn from(s: String) -> Self {
99        Param::new(s)
100    }
101}
102
103/// A function definition.
104#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
105pub struct Function {
106    /// Function name (empty for anonymous functions).
107    pub name: String,
108    /// Parameters (with optional type annotations).
109    pub params: Vec<Param>,
110    /// Optional return type annotation (e.g. `string` for `): string` in TypeScript,
111    /// `int` for `-> int` in Python).
112    #[serde(skip_serializing_if = "Option::is_none")]
113    pub return_type: Option<String>,
114    /// Function body.
115    pub body: Vec<Stmt>,
116}
117
118impl Function {
119    pub fn new(name: impl Into<String>, params: Vec<Param>, body: Vec<Stmt>) -> Self {
120        Self {
121            name: name.into(),
122            params,
123            return_type: None,
124            body,
125        }
126    }
127
128    pub fn anonymous(params: Vec<Param>, body: Vec<Stmt>) -> Self {
129        Self::new("", params, body)
130    }
131}