pr 02
This commit is contained in:
parent
6b372b2613
commit
4e66387f4e
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1907,6 +1907,7 @@ dependencies = [
|
|||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
"prometeu-abi",
|
"prometeu-abi",
|
||||||
|
"prometeu-analysis",
|
||||||
"prometeu-bytecode",
|
"prometeu-bytecode",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|||||||
54
crates/prometeu-analysis/src/interner.rs
Normal file
54
crates/prometeu-analysis/src/interner.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct NameId(pub u32);
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct NameInterner {
|
||||||
|
names: Vec<String>,
|
||||||
|
ids: HashMap<String, NameId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NameInterner {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
names: Vec::new(),
|
||||||
|
ids: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn intern(&mut self, s: &str) -> NameId {
|
||||||
|
if let Some(id) = self.ids.get(s) {
|
||||||
|
return *id;
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = NameId(self.names.len() as u32);
|
||||||
|
self.names.push(s.to_string());
|
||||||
|
self.ids.insert(self.names[id.0 as usize].clone(), id);
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resolve(&self, id: NameId) -> &str {
|
||||||
|
&self.names[id.0 as usize]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn interner_intern_resolve_roundtrip() {
|
||||||
|
let mut interner = NameInterner::new();
|
||||||
|
let id = interner.intern("foo");
|
||||||
|
assert_eq!(interner.resolve(id), "foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn interner_dedups_strings() {
|
||||||
|
let mut interner = NameInterner::new();
|
||||||
|
let id1 = interner.intern("bar");
|
||||||
|
let id2 = interner.intern("bar");
|
||||||
|
assert_eq!(id1, id2);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,9 @@
|
|||||||
pub mod ids;
|
pub mod ids;
|
||||||
pub mod span;
|
pub mod span;
|
||||||
pub mod file_db;
|
pub mod file_db;
|
||||||
|
pub mod interner;
|
||||||
|
|
||||||
pub use ids::FileId;
|
pub use ids::FileId;
|
||||||
pub use span::Span;
|
pub use span::Span;
|
||||||
pub use file_db::{FileDB, LineIndex};
|
pub use file_db::{FileDB, LineIndex};
|
||||||
|
pub use interner::{NameId, NameInterner};
|
||||||
|
|||||||
@ -16,6 +16,7 @@ include = ["../../VERSION.txt"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
prometeu-bytecode = { path = "../prometeu-bytecode" }
|
prometeu-bytecode = { path = "../prometeu-bytecode" }
|
||||||
prometeu-abi = { path = "../prometeu-abi" }
|
prometeu-abi = { path = "../prometeu-abi" }
|
||||||
|
prometeu-analysis = { path = "../prometeu-analysis" }
|
||||||
clap = { version = "4.5.54", features = ["derive"] }
|
clap = { version = "4.5.54", features = ["derive"] }
|
||||||
serde = { version = "1.0.228", features = ["derive"] }
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
serde_json = "1.0.149"
|
serde_json = "1.0.149"
|
||||||
|
|||||||
@ -15,6 +15,7 @@ use crate::frontends::pbs::types::PbsType;
|
|||||||
use crate::lowering::core_to_vm;
|
use crate::lowering::core_to_vm;
|
||||||
use crate::semantics::export_surface::ExportSurfaceKind;
|
use crate::semantics::export_surface::ExportSurfaceKind;
|
||||||
use prometeu_bytecode::{ConstantPoolEntry, DebugInfo, FunctionMeta};
|
use prometeu_bytecode::{ConstantPoolEntry, DebugInfo, FunctionMeta};
|
||||||
|
use prometeu_analysis::NameInterner;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
|
|
||||||
@ -112,6 +113,7 @@ pub fn compile_project(
|
|||||||
dep_modules: &HashMap<ProjectId, CompiledModule>,
|
dep_modules: &HashMap<ProjectId, CompiledModule>,
|
||||||
file_manager: &mut FileManager,
|
file_manager: &mut FileManager,
|
||||||
) -> Result<CompiledModule, CompileError> {
|
) -> Result<CompiledModule, CompileError> {
|
||||||
|
let mut interner = NameInterner::new();
|
||||||
// 1. Parse all files and group symbols by module
|
// 1. Parse all files and group symbols by module
|
||||||
let mut module_symbols_map: HashMap<String, ModuleSymbols> = HashMap::new();
|
let mut module_symbols_map: HashMap<String, ModuleSymbols> = HashMap::new();
|
||||||
let mut parsed_files: Vec<(String, FileNode)> = Vec::new(); // (module_path, ast)
|
let mut parsed_files: Vec<(String, FileNode)> = Vec::new(); // (module_path, ast)
|
||||||
@ -121,10 +123,10 @@ pub fn compile_project(
|
|||||||
let source_code = std::fs::read_to_string(&source_abs)?;
|
let source_code = std::fs::read_to_string(&source_abs)?;
|
||||||
let file_id = file_manager.add(source_abs.clone(), source_code.clone());
|
let file_id = file_manager.add(source_abs.clone(), source_code.clone());
|
||||||
|
|
||||||
let mut parser = Parser::new(&source_code, file_id);
|
let mut parser = Parser::new(&source_code, file_id, &mut interner);
|
||||||
let ast = parser.parse_file()?;
|
let ast = parser.parse_file()?;
|
||||||
|
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let (ts, vs) = collector.collect(&ast)?;
|
let (ts, vs) = collector.collect(&ast)?;
|
||||||
|
|
||||||
let full_path = source_rel.to_string_lossy().replace('\\', "/");
|
let full_path = source_rel.to_string_lossy().replace('\\', "/");
|
||||||
@ -145,20 +147,30 @@ pub fn compile_project(
|
|||||||
|
|
||||||
// Merge symbols
|
// Merge symbols
|
||||||
for sym in ts.symbols.into_values() {
|
for sym in ts.symbols.into_values() {
|
||||||
if let Err(existing) = ms.type_symbols.insert(sym) {
|
if let Some(existing) = ms.type_symbols.get(sym.name) {
|
||||||
return Err(DiagnosticBundle::error(
|
return Err(DiagnosticBundle::error(
|
||||||
format!("Duplicate type symbol '{}' in module '{}'", existing.name, module_path),
|
format!(
|
||||||
|
"Duplicate type symbol '{}' in module '{}'",
|
||||||
|
interner.resolve(existing.name),
|
||||||
|
module_path
|
||||||
|
),
|
||||||
Some(existing.span)
|
Some(existing.span)
|
||||||
).into());
|
).into());
|
||||||
}
|
}
|
||||||
|
let _ = ms.type_symbols.insert(sym);
|
||||||
}
|
}
|
||||||
for sym in vs.symbols.into_values() {
|
for sym in vs.symbols.into_values() {
|
||||||
if let Err(existing) = ms.value_symbols.insert(sym) {
|
if let Some(existing) = ms.value_symbols.get(sym.name) {
|
||||||
return Err(DiagnosticBundle::error(
|
return Err(DiagnosticBundle::error(
|
||||||
format!("Duplicate value symbol '{}' in module '{}'", existing.name, module_path),
|
format!(
|
||||||
|
"Duplicate value symbol '{}' in module '{}'",
|
||||||
|
interner.resolve(existing.name),
|
||||||
|
module_path
|
||||||
|
),
|
||||||
Some(existing.span)
|
Some(existing.span)
|
||||||
).into());
|
).into());
|
||||||
}
|
}
|
||||||
|
let _ = ms.value_symbols.insert(sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
parsed_files.push((module_path, ast));
|
parsed_files.push((module_path, ast));
|
||||||
@ -180,7 +192,7 @@ pub fn compile_project(
|
|||||||
let ms = all_visible_modules.entry(synthetic_module_path.clone()).or_insert_with(ModuleSymbols::new);
|
let ms = all_visible_modules.entry(synthetic_module_path.clone()).or_insert_with(ModuleSymbols::new);
|
||||||
|
|
||||||
let sym = Symbol {
|
let sym = Symbol {
|
||||||
name: key.symbol_name.clone(),
|
name: interner.intern(&key.symbol_name),
|
||||||
kind: match key.kind {
|
kind: match key.kind {
|
||||||
ExportSurfaceKind::Service => SymbolKind::Service,
|
ExportSurfaceKind::Service => SymbolKind::Service,
|
||||||
ExportSurfaceKind::DeclareType => {
|
ExportSurfaceKind::DeclareType => {
|
||||||
@ -200,21 +212,23 @@ pub fn compile_project(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if sym.namespace == Namespace::Type {
|
if sym.namespace == Namespace::Type {
|
||||||
if let Err(existing) = ms.type_symbols.insert(sym.clone()) {
|
if let Some(existing) = ms.type_symbols.get(sym.name) {
|
||||||
return Err(CompileError::DuplicateExport {
|
return Err(CompileError::DuplicateExport {
|
||||||
symbol: sym.name,
|
symbol: interner.resolve(sym.name).to_string(),
|
||||||
first_dep: existing.origin.unwrap_or_else(|| "unknown".to_string()),
|
first_dep: existing.origin.clone().unwrap_or_else(|| "unknown".to_string()),
|
||||||
second_dep: sym.origin.unwrap_or_else(|| "unknown".to_string()),
|
second_dep: sym.origin.unwrap_or_else(|| "unknown".to_string()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
let _ = ms.type_symbols.insert(sym.clone());
|
||||||
} else {
|
} else {
|
||||||
if let Err(existing) = ms.value_symbols.insert(sym.clone()) {
|
if let Some(existing) = ms.value_symbols.get(sym.name) {
|
||||||
return Err(CompileError::DuplicateExport {
|
return Err(CompileError::DuplicateExport {
|
||||||
symbol: sym.name,
|
symbol: interner.resolve(sym.name).to_string(),
|
||||||
first_dep: existing.origin.unwrap_or_else(|| "unknown".to_string()),
|
first_dep: existing.origin.clone().unwrap_or_else(|| "unknown".to_string()),
|
||||||
second_dep: sym.origin.unwrap_or_else(|| "unknown".to_string()),
|
second_dep: sym.origin.unwrap_or_else(|| "unknown".to_string()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
let _ = ms.value_symbols.insert(sym.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -231,7 +245,7 @@ pub fn compile_project(
|
|||||||
|
|
||||||
for (module_path, ast) in &parsed_files {
|
for (module_path, ast) in &parsed_files {
|
||||||
let ms = module_symbols_map.get(module_path).unwrap();
|
let ms = module_symbols_map.get(module_path).unwrap();
|
||||||
let mut resolver = Resolver::new(ms, &module_provider);
|
let mut resolver = Resolver::new(ms, &module_provider, &interner);
|
||||||
resolver.resolve(ast)?;
|
resolver.resolve(ast)?;
|
||||||
|
|
||||||
// Capture imported symbols
|
// Capture imported symbols
|
||||||
@ -240,7 +254,7 @@ pub fn compile_project(
|
|||||||
// TypeChecker also needs &mut ModuleSymbols
|
// TypeChecker also needs &mut ModuleSymbols
|
||||||
let mut ms_mut = module_symbols_map.get_mut(module_path).unwrap();
|
let mut ms_mut = module_symbols_map.get_mut(module_path).unwrap();
|
||||||
let imported = file_imported_symbols.get(module_path).unwrap();
|
let imported = file_imported_symbols.get(module_path).unwrap();
|
||||||
let mut typechecker = TypeChecker::new(&mut ms_mut, imported, &module_provider);
|
let mut typechecker = TypeChecker::new(&mut ms_mut, imported, &module_provider, &interner);
|
||||||
typechecker.check(ast)?;
|
typechecker.check(ast)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,7 +269,7 @@ pub fn compile_project(
|
|||||||
for (module_path, ast) in &parsed_files {
|
for (module_path, ast) in &parsed_files {
|
||||||
let ms = module_symbols_map.get(module_path).unwrap();
|
let ms = module_symbols_map.get(module_path).unwrap();
|
||||||
let imported = file_imported_symbols.get(module_path).unwrap();
|
let imported = file_imported_symbols.get(module_path).unwrap();
|
||||||
let lowerer = Lowerer::new(ms, imported);
|
let lowerer = Lowerer::new(ms, imported, &interner);
|
||||||
let program = lowerer.lower_file(ast, module_path)?;
|
let program = lowerer.lower_file(ast, module_path)?;
|
||||||
|
|
||||||
// Combine program into combined_program
|
// Combine program into combined_program
|
||||||
@ -281,7 +295,7 @@ pub fn compile_project(
|
|||||||
if let Some(surface_kind) = ExportSurfaceKind::from_symbol_kind(sym.kind) {
|
if let Some(surface_kind) = ExportSurfaceKind::from_symbol_kind(sym.kind) {
|
||||||
exports.insert(ExportKey {
|
exports.insert(ExportKey {
|
||||||
module_path: module_path.clone(),
|
module_path: module_path.clone(),
|
||||||
symbol_name: sym.name.clone(),
|
symbol_name: interner.resolve(sym.name).to_string(),
|
||||||
kind: surface_kind,
|
kind: surface_kind,
|
||||||
}, ExportMetadata {
|
}, ExportMetadata {
|
||||||
func_idx: None,
|
func_idx: None,
|
||||||
@ -295,11 +309,15 @@ pub fn compile_project(
|
|||||||
if sym.visibility == Visibility::Pub {
|
if sym.visibility == Visibility::Pub {
|
||||||
if let Some(surface_kind) = ExportSurfaceKind::from_symbol_kind(sym.kind) {
|
if let Some(surface_kind) = ExportSurfaceKind::from_symbol_kind(sym.kind) {
|
||||||
// Find func_idx if it's a function or service
|
// Find func_idx if it's a function or service
|
||||||
let func_idx = vm_module.functions.iter().position(|f| f.name == sym.name).map(|i| i as u32);
|
let func_idx = vm_module
|
||||||
|
.functions
|
||||||
|
.iter()
|
||||||
|
.position(|f| f.name == interner.resolve(sym.name))
|
||||||
|
.map(|i| i as u32);
|
||||||
|
|
||||||
exports.insert(ExportKey {
|
exports.insert(ExportKey {
|
||||||
module_path: module_path.clone(),
|
module_path: module_path.clone(),
|
||||||
symbol_name: sym.name.clone(),
|
symbol_name: interner.resolve(sym.name).to_string(),
|
||||||
kind: surface_kind,
|
kind: surface_kind,
|
||||||
}, ExportMetadata {
|
}, ExportMetadata {
|
||||||
func_idx,
|
func_idx,
|
||||||
@ -312,7 +330,12 @@ pub fn compile_project(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 6. Collect symbols
|
// 6. Collect symbols
|
||||||
let project_symbols = crate::common::symbols::collect_symbols(&step.project_id.name, &module_symbols_map, file_manager);
|
let project_symbols = crate::common::symbols::collect_symbols(
|
||||||
|
&step.project_id.name,
|
||||||
|
&module_symbols_map,
|
||||||
|
file_manager,
|
||||||
|
&interner,
|
||||||
|
);
|
||||||
|
|
||||||
// 7. Collect imports from unresolved labels
|
// 7. Collect imports from unresolved labels
|
||||||
let mut imports = Vec::new();
|
let mut imports = Vec::new();
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use crate::common::spans::Span;
|
use crate::common::spans::Span;
|
||||||
|
use prometeu_analysis::NameInterner;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
@ -60,19 +61,20 @@ pub fn collect_symbols(
|
|||||||
project_id: &str,
|
project_id: &str,
|
||||||
module_symbols: &HashMap<String, crate::frontends::pbs::symbols::ModuleSymbols>,
|
module_symbols: &HashMap<String, crate::frontends::pbs::symbols::ModuleSymbols>,
|
||||||
file_manager: &crate::common::files::FileManager,
|
file_manager: &crate::common::files::FileManager,
|
||||||
|
interner: &NameInterner,
|
||||||
) -> Vec<Symbol> {
|
) -> Vec<Symbol> {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
|
|
||||||
for (module_path, ms) in module_symbols {
|
for (module_path, ms) in module_symbols {
|
||||||
// Collect from type_symbols
|
// Collect from type_symbols
|
||||||
for sym in ms.type_symbols.symbols.values() {
|
for sym in ms.type_symbols.symbols.values() {
|
||||||
if let Some(s) = convert_symbol(project_id, module_path, sym, file_manager) {
|
if let Some(s) = convert_symbol(project_id, module_path, sym, file_manager, interner) {
|
||||||
result.push(s);
|
result.push(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Collect from value_symbols
|
// Collect from value_symbols
|
||||||
for sym in ms.value_symbols.symbols.values() {
|
for sym in ms.value_symbols.symbols.values() {
|
||||||
if let Some(s) = convert_symbol(project_id, module_path, sym, file_manager) {
|
if let Some(s) = convert_symbol(project_id, module_path, sym, file_manager, interner) {
|
||||||
result.push(s);
|
result.push(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,6 +96,7 @@ fn convert_symbol(
|
|||||||
module_path: &str,
|
module_path: &str,
|
||||||
sym: &crate::frontends::pbs::symbols::Symbol,
|
sym: &crate::frontends::pbs::symbols::Symbol,
|
||||||
file_manager: &crate::common::files::FileManager,
|
file_manager: &crate::common::files::FileManager,
|
||||||
|
interner: &NameInterner,
|
||||||
) -> Option<Symbol> {
|
) -> Option<Symbol> {
|
||||||
use crate::frontends::pbs::symbols::{SymbolKind, Visibility};
|
use crate::frontends::pbs::symbols::{SymbolKind, Visibility};
|
||||||
|
|
||||||
@ -130,11 +133,12 @@ fn convert_symbol(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let hash = decl_span.compute_hash();
|
let hash = decl_span.compute_hash();
|
||||||
let id = format!("{}:{}:{}:{}:{:016x}", project_id, kind, module_path, sym.name, hash);
|
let name = interner.resolve(sym.name).to_string();
|
||||||
|
let id = format!("{}:{}:{}:{}:{:016x}", project_id, kind, module_path, name, hash);
|
||||||
|
|
||||||
Some(Symbol {
|
Some(Symbol {
|
||||||
id,
|
id,
|
||||||
name: sym.name.clone(),
|
name,
|
||||||
kind: kind.to_string(),
|
kind: kind.to_string(),
|
||||||
exported,
|
exported,
|
||||||
module_path: module_path.to_string(),
|
module_path: module_path.to_string(),
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use crate::common::spans::Span;
|
use crate::common::spans::Span;
|
||||||
|
use prometeu_analysis::NameId;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
@ -56,22 +57,22 @@ pub struct ImportNode {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct ImportSpecNode {
|
pub struct ImportSpecNode {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub path: Vec<String>,
|
pub path: Vec<NameId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct ServiceDeclNode {
|
pub struct ServiceDeclNode {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub vis: Option<String>, // "pub" | "mod"
|
pub vis: Option<String>, // "pub" | "mod"
|
||||||
pub name: String,
|
pub name: NameId,
|
||||||
pub extends: Option<String>,
|
pub extends: Option<NameId>,
|
||||||
pub members: Vec<Node>, // ServiceFnSig
|
pub members: Vec<Node>, // ServiceFnSig
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct ServiceFnSigNode {
|
pub struct ServiceFnSigNode {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub name: String,
|
pub name: NameId,
|
||||||
pub params: Vec<ParamNode>,
|
pub params: Vec<ParamNode>,
|
||||||
pub ret: Box<Node>, // TypeName or TypeApp
|
pub ret: Box<Node>, // TypeName or TypeApp
|
||||||
}
|
}
|
||||||
@ -79,7 +80,7 @@ pub struct ServiceFnSigNode {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct ParamNode {
|
pub struct ParamNode {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub name: String,
|
pub name: NameId,
|
||||||
pub ty: Box<Node>,
|
pub ty: Box<Node>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +88,7 @@ pub struct ParamNode {
|
|||||||
pub struct FnDeclNode {
|
pub struct FnDeclNode {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub vis: Option<String>,
|
pub vis: Option<String>,
|
||||||
pub name: String,
|
pub name: NameId,
|
||||||
pub params: Vec<ParamNode>,
|
pub params: Vec<ParamNode>,
|
||||||
pub ret: Option<Box<Node>>,
|
pub ret: Option<Box<Node>>,
|
||||||
pub else_fallback: Option<Box<Node>>, // Block
|
pub else_fallback: Option<Box<Node>>, // Block
|
||||||
@ -99,7 +100,7 @@ pub struct TypeDeclNode {
|
|||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub vis: Option<String>,
|
pub vis: Option<String>,
|
||||||
pub type_kind: String, // "struct" | "contract" | "error"
|
pub type_kind: String, // "struct" | "contract" | "error"
|
||||||
pub name: String,
|
pub name: NameId,
|
||||||
pub is_host: bool,
|
pub is_host: bool,
|
||||||
pub params: Vec<ParamNode>, // fields for struct/error
|
pub params: Vec<ParamNode>, // fields for struct/error
|
||||||
pub constructors: Vec<ConstructorDeclNode>, // [ ... ]
|
pub constructors: Vec<ConstructorDeclNode>, // [ ... ]
|
||||||
@ -112,14 +113,14 @@ pub struct ConstructorDeclNode {
|
|||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub params: Vec<ParamNode>,
|
pub params: Vec<ParamNode>,
|
||||||
pub initializers: Vec<Node>,
|
pub initializers: Vec<Node>,
|
||||||
pub name: String,
|
pub name: NameId,
|
||||||
pub body: Box<Node>, // BlockNode
|
pub body: Box<Node>, // BlockNode
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct ConstantDeclNode {
|
pub struct ConstantDeclNode {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub name: String,
|
pub name: NameId,
|
||||||
pub value: Box<Node>,
|
pub value: Box<Node>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +134,7 @@ pub struct TypeBodyNode {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct TypeMemberNode {
|
pub struct TypeMemberNode {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub name: String,
|
pub name: NameId,
|
||||||
pub ty: Box<Node>,
|
pub ty: Box<Node>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +148,7 @@ pub struct BlockNode {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct LetStmtNode {
|
pub struct LetStmtNode {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub name: String,
|
pub name: NameId,
|
||||||
pub is_mut: bool,
|
pub is_mut: bool,
|
||||||
pub ty: Option<Box<Node>>,
|
pub ty: Option<Box<Node>>,
|
||||||
pub init: Box<Node>,
|
pub init: Box<Node>,
|
||||||
@ -192,7 +193,7 @@ pub struct StringLitNode {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct IdentNode {
|
pub struct IdentNode {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub name: String,
|
pub name: NameId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
@ -248,13 +249,13 @@ pub struct WhenArmNode {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct TypeNameNode {
|
pub struct TypeNameNode {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub name: String,
|
pub name: NameId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct TypeAppNode {
|
pub struct TypeAppNode {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub base: String,
|
pub base: NameId,
|
||||||
pub args: Vec<Node>,
|
pub args: Vec<Node>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +269,7 @@ pub struct AllocNode {
|
|||||||
pub struct MutateNode {
|
pub struct MutateNode {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub target: Box<Node>,
|
pub target: Box<Node>,
|
||||||
pub binding: String,
|
pub binding: NameId,
|
||||||
pub body: Box<Node>, // BlockNode
|
pub body: Box<Node>, // BlockNode
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,7 +277,7 @@ pub struct MutateNode {
|
|||||||
pub struct BorrowNode {
|
pub struct BorrowNode {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub target: Box<Node>,
|
pub target: Box<Node>,
|
||||||
pub binding: String,
|
pub binding: NameId,
|
||||||
pub body: Box<Node>, // BlockNode
|
pub body: Box<Node>, // BlockNode
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,7 +285,7 @@ pub struct BorrowNode {
|
|||||||
pub struct PeekNode {
|
pub struct PeekNode {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub target: Box<Node>,
|
pub target: Box<Node>,
|
||||||
pub binding: String,
|
pub binding: NameId,
|
||||||
pub body: Box<Node>, // BlockNode
|
pub body: Box<Node>, // BlockNode
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,5 +293,5 @@ pub struct PeekNode {
|
|||||||
pub struct MemberAccessNode {
|
pub struct MemberAccessNode {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub object: Box<Node>,
|
pub object: Box<Node>,
|
||||||
pub member: String,
|
pub member: NameId,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,16 +2,19 @@ use crate::common::diagnostics::{Diagnostic, DiagnosticBundle, DiagnosticLevel};
|
|||||||
use crate::frontends::pbs::ast::*;
|
use crate::frontends::pbs::ast::*;
|
||||||
use crate::frontends::pbs::symbols::*;
|
use crate::frontends::pbs::symbols::*;
|
||||||
use crate::semantics::export_surface::ExportSurfaceKind;
|
use crate::semantics::export_surface::ExportSurfaceKind;
|
||||||
|
use prometeu_analysis::NameInterner;
|
||||||
|
|
||||||
pub struct SymbolCollector {
|
pub struct SymbolCollector<'a> {
|
||||||
|
interner: &'a NameInterner,
|
||||||
type_symbols: SymbolTable,
|
type_symbols: SymbolTable,
|
||||||
value_symbols: SymbolTable,
|
value_symbols: SymbolTable,
|
||||||
diagnostics: Vec<Diagnostic>,
|
diagnostics: Vec<Diagnostic>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SymbolCollector {
|
impl<'a> SymbolCollector<'a> {
|
||||||
pub fn new() -> Self {
|
pub fn new(interner: &'a NameInterner) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
interner,
|
||||||
type_symbols: SymbolTable::new(),
|
type_symbols: SymbolTable::new(),
|
||||||
value_symbols: SymbolTable::new(),
|
value_symbols: SymbolTable::new(),
|
||||||
diagnostics: Vec::new(),
|
diagnostics: Vec::new(),
|
||||||
@ -113,35 +116,43 @@ impl SymbolCollector {
|
|||||||
|
|
||||||
fn insert_type_symbol(&mut self, symbol: Symbol) {
|
fn insert_type_symbol(&mut self, symbol: Symbol) {
|
||||||
// Check for collision in value namespace first
|
// Check for collision in value namespace first
|
||||||
if let Some(existing) = self.value_symbols.get(&symbol.name) {
|
if let Some(existing) = self.value_symbols.get(symbol.name) {
|
||||||
let existing = existing.clone();
|
let existing = existing.clone();
|
||||||
self.error_collision(&symbol, &existing);
|
self.error_collision(&symbol, &existing);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(existing) = self.type_symbols.insert(symbol.clone()) {
|
if let Err(()) = self.type_symbols.insert(symbol.clone()) {
|
||||||
|
if let Some(existing) = self.type_symbols.get(symbol.name).cloned() {
|
||||||
self.error_duplicate(&symbol, &existing);
|
self.error_duplicate(&symbol, &existing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn insert_value_symbol(&mut self, symbol: Symbol) {
|
fn insert_value_symbol(&mut self, symbol: Symbol) {
|
||||||
// Check for collision in type namespace first
|
// Check for collision in type namespace first
|
||||||
if let Some(existing) = self.type_symbols.get(&symbol.name) {
|
if let Some(existing) = self.type_symbols.get(symbol.name) {
|
||||||
let existing = existing.clone();
|
let existing = existing.clone();
|
||||||
self.error_collision(&symbol, &existing);
|
self.error_collision(&symbol, &existing);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(existing) = self.value_symbols.insert(symbol.clone()) {
|
if let Err(()) = self.value_symbols.insert(symbol.clone()) {
|
||||||
|
if let Some(existing) = self.value_symbols.get(symbol.name).cloned() {
|
||||||
self.error_duplicate(&symbol, &existing);
|
self.error_duplicate(&symbol, &existing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn error_duplicate(&mut self, symbol: &Symbol, existing: &Symbol) {
|
fn error_duplicate(&mut self, symbol: &Symbol, existing: &Symbol) {
|
||||||
self.diagnostics.push(Diagnostic {
|
self.diagnostics.push(Diagnostic {
|
||||||
level: DiagnosticLevel::Error,
|
level: DiagnosticLevel::Error,
|
||||||
code: Some("E_RESOLVE_DUPLICATE_SYMBOL".to_string()),
|
code: Some("E_RESOLVE_DUPLICATE_SYMBOL".to_string()),
|
||||||
message: format!("Duplicate symbol '{}' already defined at {:?}", symbol.name, existing.span),
|
message: format!(
|
||||||
|
"Duplicate symbol '{}' already defined at {:?}",
|
||||||
|
self.interner.resolve(symbol.name),
|
||||||
|
existing.span
|
||||||
|
),
|
||||||
span: Some(symbol.span),
|
span: Some(symbol.span),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -152,7 +163,9 @@ impl SymbolCollector {
|
|||||||
code: Some("E_RESOLVE_NAMESPACE_COLLISION".to_string()),
|
code: Some("E_RESOLVE_NAMESPACE_COLLISION".to_string()),
|
||||||
message: format!(
|
message: format!(
|
||||||
"DebugSymbol '{}' collides with another symbol in the {:?} namespace defined at {:?}",
|
"DebugSymbol '{}' collides with another symbol in the {:?} namespace defined at {:?}",
|
||||||
symbol.name, existing.namespace, existing.span
|
self.interner.resolve(symbol.name),
|
||||||
|
existing.namespace,
|
||||||
|
existing.span
|
||||||
),
|
),
|
||||||
span: Some(symbol.span),
|
span: Some(symbol.span),
|
||||||
});
|
});
|
||||||
|
|||||||
@ -7,6 +7,7 @@ use crate::frontends::pbs::types::PbsType;
|
|||||||
use crate::ir_core;
|
use crate::ir_core;
|
||||||
use crate::ir_core::ids::{FieldId, FunctionId, TypeId, ValueId};
|
use crate::ir_core::ids::{FieldId, FunctionId, TypeId, ValueId};
|
||||||
use crate::ir_core::{Block, Function, Instr, InstrKind, Module, Param, Program, Terminator, Type};
|
use crate::ir_core::{Block, Function, Instr, InstrKind, Module, Param, Program, Terminator, Type};
|
||||||
|
use prometeu_analysis::NameInterner;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -18,6 +19,7 @@ struct LocalInfo {
|
|||||||
pub struct Lowerer<'a> {
|
pub struct Lowerer<'a> {
|
||||||
module_symbols: &'a ModuleSymbols,
|
module_symbols: &'a ModuleSymbols,
|
||||||
imported_symbols: &'a ModuleSymbols,
|
imported_symbols: &'a ModuleSymbols,
|
||||||
|
interner: &'a NameInterner,
|
||||||
program: Program,
|
program: Program,
|
||||||
current_function: Option<Function>,
|
current_function: Option<Function>,
|
||||||
current_block: Option<Block>,
|
current_block: Option<Block>,
|
||||||
@ -38,7 +40,11 @@ pub struct Lowerer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Lowerer<'a> {
|
impl<'a> Lowerer<'a> {
|
||||||
pub fn new(module_symbols: &'a ModuleSymbols, imported_symbols: &'a ModuleSymbols) -> Self {
|
pub fn new(
|
||||||
|
module_symbols: &'a ModuleSymbols,
|
||||||
|
imported_symbols: &'a ModuleSymbols,
|
||||||
|
interner: &'a NameInterner,
|
||||||
|
) -> Self {
|
||||||
let mut field_offsets = HashMap::new();
|
let mut field_offsets = HashMap::new();
|
||||||
field_offsets.insert(FieldId(0), 0); // V0 hardcoded field resolution foundation
|
field_offsets.insert(FieldId(0), 0); // V0 hardcoded field resolution foundation
|
||||||
|
|
||||||
@ -51,6 +57,7 @@ impl<'a> Lowerer<'a> {
|
|||||||
Self {
|
Self {
|
||||||
module_symbols,
|
module_symbols,
|
||||||
imported_symbols,
|
imported_symbols,
|
||||||
|
interner,
|
||||||
program: Program {
|
program: Program {
|
||||||
const_pool: ir_core::ConstPool::new(),
|
const_pool: ir_core::ConstPool::new(),
|
||||||
modules: Vec::new(),
|
modules: Vec::new(),
|
||||||
@ -91,12 +98,14 @@ impl<'a> Lowerer<'a> {
|
|||||||
if let Node::FnDecl(n) = decl {
|
if let Node::FnDecl(n) = decl {
|
||||||
let id = FunctionId(self.next_func_id);
|
let id = FunctionId(self.next_func_id);
|
||||||
self.next_func_id += 1;
|
self.next_func_id += 1;
|
||||||
self.function_ids.insert(n.name.clone(), id);
|
self.function_ids
|
||||||
|
.insert(self.interner.resolve(n.name).to_string(), id);
|
||||||
}
|
}
|
||||||
if let Node::TypeDecl(n) = decl {
|
if let Node::TypeDecl(n) = decl {
|
||||||
let id = TypeId(self.next_type_id);
|
let id = TypeId(self.next_type_id);
|
||||||
self.next_type_id += 1;
|
self.next_type_id += 1;
|
||||||
self.type_ids.insert(n.name.clone(), id);
|
self.type_ids
|
||||||
|
.insert(self.interner.resolve(n.name).to_string(), id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,7 +114,7 @@ impl<'a> Lowerer<'a> {
|
|||||||
for decl in &file.decls {
|
for decl in &file.decls {
|
||||||
if let Node::TypeDecl(n) = decl {
|
if let Node::TypeDecl(n) = decl {
|
||||||
if n.type_kind == "struct" {
|
if n.type_kind == "struct" {
|
||||||
struct_nodes.insert(n.name.clone(), n);
|
struct_nodes.insert(self.interner.resolve(n.name).to_string(), n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,11 +152,12 @@ impl<'a> Lowerer<'a> {
|
|||||||
|
|
||||||
for decl in &file.decls {
|
for decl in &file.decls {
|
||||||
if let Node::TypeDecl(n) = decl {
|
if let Node::TypeDecl(n) = decl {
|
||||||
|
let type_name = self.interner.resolve(n.name).to_string();
|
||||||
let mut constants = HashMap::new();
|
let mut constants = HashMap::new();
|
||||||
for c in &n.constants {
|
for c in &n.constants {
|
||||||
constants.insert(c.name.clone(), *c.value.clone());
|
constants.insert(self.interner.resolve(c.name).to_string(), *c.value.clone());
|
||||||
}
|
}
|
||||||
self.type_constants.insert(n.name.clone(), constants);
|
self.type_constants.insert(type_name.clone(), constants);
|
||||||
|
|
||||||
let mut ctors = HashMap::new();
|
let mut ctors = HashMap::new();
|
||||||
|
|
||||||
@ -166,20 +176,20 @@ impl<'a> Lowerer<'a> {
|
|||||||
span: n.span,
|
span: n.span,
|
||||||
params,
|
params,
|
||||||
initializers,
|
initializers,
|
||||||
name: n.name.clone(),
|
name: n.name,
|
||||||
body: Box::new(Node::Block(BlockNode {
|
body: Box::new(Node::Block(BlockNode {
|
||||||
span: n.span,
|
span: n.span,
|
||||||
stmts: Vec::new(),
|
stmts: Vec::new(),
|
||||||
tail: None,
|
tail: None,
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
ctors.insert(n.name.clone(), default_ctor);
|
ctors.insert(type_name.clone(), default_ctor);
|
||||||
}
|
}
|
||||||
|
|
||||||
for ctor in &n.constructors {
|
for ctor in &n.constructors {
|
||||||
ctors.insert(ctor.name.clone(), ctor.clone());
|
ctors.insert(self.interner.resolve(ctor.name).to_string(), ctor.clone());
|
||||||
}
|
}
|
||||||
self.struct_constructors.insert(n.name.clone(), ctors);
|
self.struct_constructors.insert(type_name, ctors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,7 +215,8 @@ impl<'a> Lowerer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn lower_function(&mut self, n: &FnDeclNode) -> Result<Function, ()> {
|
fn lower_function(&mut self, n: &FnDeclNode) -> Result<Function, ()> {
|
||||||
let func_id = *self.function_ids.get(&n.name).unwrap();
|
let func_name = self.interner.resolve(n.name).to_string();
|
||||||
|
let func_id = *self.function_ids.get(&func_name).unwrap();
|
||||||
self.next_block_id = 0;
|
self.next_block_id = 0;
|
||||||
self.local_vars = vec![HashMap::new()];
|
self.local_vars = vec![HashMap::new()];
|
||||||
self.max_slots_used = 0;
|
self.max_slots_used = 0;
|
||||||
@ -217,10 +228,16 @@ impl<'a> Lowerer<'a> {
|
|||||||
let ty = self.lower_type_node(¶m.ty);
|
let ty = self.lower_type_node(¶m.ty);
|
||||||
let slots = self.get_type_slots(&ty);
|
let slots = self.get_type_slots(&ty);
|
||||||
params.push(Param {
|
params.push(Param {
|
||||||
name: param.name.clone(),
|
name: self.interner.resolve(param.name).to_string(),
|
||||||
ty: ty.clone(),
|
ty: ty.clone(),
|
||||||
});
|
});
|
||||||
self.local_vars[0].insert(param.name.clone(), LocalInfo { slot: param_slots, ty: ty.clone() });
|
self.local_vars[0].insert(
|
||||||
|
self.interner.resolve(param.name).to_string(),
|
||||||
|
LocalInfo {
|
||||||
|
slot: param_slots,
|
||||||
|
ty: ty.clone(),
|
||||||
|
},
|
||||||
|
);
|
||||||
for i in 0..slots {
|
for i in 0..slots {
|
||||||
local_types.insert(param_slots + i, ty.clone());
|
local_types.insert(param_slots + i, ty.clone());
|
||||||
}
|
}
|
||||||
@ -237,7 +254,7 @@ impl<'a> Lowerer<'a> {
|
|||||||
|
|
||||||
let func = Function {
|
let func = Function {
|
||||||
id: func_id,
|
id: func_id,
|
||||||
name: n.name.clone(),
|
name: func_name,
|
||||||
params,
|
params,
|
||||||
return_type: ret_ty,
|
return_type: ret_ty,
|
||||||
blocks: Vec::new(),
|
blocks: Vec::new(),
|
||||||
@ -325,11 +342,12 @@ impl<'a> Lowerer<'a> {
|
|||||||
fn get_type_id_and_slots(&mut self, node: &Node) -> Result<(TypeId, u32), ()> {
|
fn get_type_id_and_slots(&mut self, node: &Node) -> Result<(TypeId, u32), ()> {
|
||||||
match node {
|
match node {
|
||||||
Node::TypeName(n) => {
|
Node::TypeName(n) => {
|
||||||
let slots = self.struct_slots.get(&n.name).cloned().unwrap_or(1);
|
let name = self.interner.resolve(n.name);
|
||||||
let id = self.get_or_create_type_id(&n.name);
|
let slots = self.struct_slots.get(name).cloned().unwrap_or(1);
|
||||||
|
let id = self.get_or_create_type_id(name);
|
||||||
Ok((id, slots))
|
Ok((id, slots))
|
||||||
}
|
}
|
||||||
Node::TypeApp(ta) if ta.base == "array" => {
|
Node::TypeApp(ta) if self.interner.resolve(ta.base) == "array" => {
|
||||||
let size = if ta.args.len() > 1 {
|
let size = if ta.args.len() > 1 {
|
||||||
if let Node::IntLit(il) = &ta.args[1] {
|
if let Node::IntLit(il) = &ta.args[1] {
|
||||||
il.value as u32
|
il.value as u32
|
||||||
@ -376,7 +394,7 @@ impl<'a> Lowerer<'a> {
|
|||||||
|
|
||||||
// 4. Bind view to local
|
// 4. Bind view to local
|
||||||
self.local_vars.push(HashMap::new());
|
self.local_vars.push(HashMap::new());
|
||||||
let view_slot = self.add_local_to_scope(n.binding.to_string(), Type::Int);
|
let view_slot = self.add_local_to_scope(self.interner.resolve(n.binding).to_string(), Type::Int);
|
||||||
self.emit(InstrKind::SetLocal(view_slot));
|
self.emit(InstrKind::SetLocal(view_slot));
|
||||||
|
|
||||||
// 5. Body
|
// 5. Body
|
||||||
@ -403,7 +421,7 @@ impl<'a> Lowerer<'a> {
|
|||||||
|
|
||||||
// 4. Bind view to local
|
// 4. Bind view to local
|
||||||
self.local_vars.push(HashMap::new());
|
self.local_vars.push(HashMap::new());
|
||||||
let view_slot = self.add_local_to_scope(n.binding.to_string(), Type::Int);
|
let view_slot = self.add_local_to_scope(self.interner.resolve(n.binding).to_string(), Type::Int);
|
||||||
self.emit(InstrKind::SetLocal(view_slot));
|
self.emit(InstrKind::SetLocal(view_slot));
|
||||||
|
|
||||||
// 5. Body
|
// 5. Body
|
||||||
@ -430,7 +448,7 @@ impl<'a> Lowerer<'a> {
|
|||||||
|
|
||||||
// 4. Bind view to local
|
// 4. Bind view to local
|
||||||
self.local_vars.push(HashMap::new());
|
self.local_vars.push(HashMap::new());
|
||||||
let view_slot = self.add_local_to_scope(n.binding.to_string(), Type::Int);
|
let view_slot = self.add_local_to_scope(self.interner.resolve(n.binding).to_string(), Type::Int);
|
||||||
self.emit(InstrKind::SetLocal(view_slot));
|
self.emit(InstrKind::SetLocal(view_slot));
|
||||||
|
|
||||||
// 5. Body
|
// 5. Body
|
||||||
@ -465,7 +483,9 @@ impl<'a> Lowerer<'a> {
|
|||||||
if let Node::Call(call) = &*n.init {
|
if let Node::Call(call) = &*n.init {
|
||||||
if let Node::MemberAccess(ma) = &*call.callee {
|
if let Node::MemberAccess(ma) = &*call.callee {
|
||||||
if let Node::Ident(obj) = &*ma.object {
|
if let Node::Ident(obj) = &*ma.object {
|
||||||
match (obj.name.as_str(), ma.member.as_str()) {
|
let obj_name = self.interner.resolve(obj.name);
|
||||||
|
let member_name = self.interner.resolve(ma.member);
|
||||||
|
match (obj_name, member_name) {
|
||||||
("Input", "pad") => Type::Struct("Pad".to_string()),
|
("Input", "pad") => Type::Struct("Pad".to_string()),
|
||||||
("Input", "touch") => Type::Struct("Touch".to_string()),
|
("Input", "touch") => Type::Struct("Touch".to_string()),
|
||||||
_ => Type::Int,
|
_ => Type::Int,
|
||||||
@ -476,7 +496,7 @@ impl<'a> Lowerer<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let slots = self.get_type_slots(&ty);
|
let slots = self.get_type_slots(&ty);
|
||||||
let slot = self.add_local_to_scope(n.name.clone(), ty);
|
let slot = self.add_local_to_scope(self.interner.resolve(n.name).to_string(), ty);
|
||||||
|
|
||||||
for i in (0..slots).rev() {
|
for i in (0..slots).rev() {
|
||||||
self.emit(InstrKind::SetLocal(slot + i));
|
self.emit(InstrKind::SetLocal(slot + i));
|
||||||
@ -493,7 +513,8 @@ impl<'a> Lowerer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn lower_ident(&mut self, n: &IdentNode) -> Result<(), ()> {
|
fn lower_ident(&mut self, n: &IdentNode) -> Result<(), ()> {
|
||||||
if let Some(info) = self.find_local(&n.name) {
|
let name_str = self.interner.resolve(n.name);
|
||||||
|
if let Some(info) = self.find_local(name_str) {
|
||||||
let slots = self.get_type_slots(&info.ty);
|
let slots = self.get_type_slots(&info.ty);
|
||||||
for i in 0..slots {
|
for i in 0..slots {
|
||||||
self.emit(InstrKind::GetLocal(info.slot + i));
|
self.emit(InstrKind::GetLocal(info.slot + i));
|
||||||
@ -501,7 +522,7 @@ impl<'a> Lowerer<'a> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
// Check for special identifiers
|
// Check for special identifiers
|
||||||
match n.name.as_str() {
|
match name_str {
|
||||||
"true" => {
|
"true" => {
|
||||||
let id = self.program.const_pool.add_int(1);
|
let id = self.program.const_pool.add_int(1);
|
||||||
self.emit(InstrKind::PushConst(id));
|
self.emit(InstrKind::PushConst(id));
|
||||||
@ -522,12 +543,20 @@ impl<'a> Lowerer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if it's a function (for first-class functions if supported)
|
// Check if it's a function (for first-class functions if supported)
|
||||||
if let Some(_id) = self.function_ids.get(&n.name) {
|
if let Some(_id) = self.function_ids.get(name_str) {
|
||||||
// Push function reference? Not in v0.
|
// Push function reference? Not in v0.
|
||||||
self.error("E_LOWER_UNSUPPORTED", format!("First-class function reference '{}' not supported", n.name), n.span);
|
self.error(
|
||||||
|
"E_LOWER_UNSUPPORTED",
|
||||||
|
format!("First-class function reference '{}' not supported", name_str),
|
||||||
|
n.span,
|
||||||
|
);
|
||||||
Err(())
|
Err(())
|
||||||
} else {
|
} else {
|
||||||
self.error("E_RESOLVE_UNDEFINED", format!("Undefined identifier '{}'", n.name), n.span);
|
self.error(
|
||||||
|
"E_RESOLVE_UNDEFINED",
|
||||||
|
format!("Undefined identifier '{}'", name_str),
|
||||||
|
n.span,
|
||||||
|
);
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -535,17 +564,19 @@ impl<'a> Lowerer<'a> {
|
|||||||
|
|
||||||
fn lower_member_access(&mut self, n: &MemberAccessNode) -> Result<(), ()> {
|
fn lower_member_access(&mut self, n: &MemberAccessNode) -> Result<(), ()> {
|
||||||
if let Node::Ident(id) = &*n.object {
|
if let Node::Ident(id) = &*n.object {
|
||||||
if let Some(constants) = self.type_constants.get(&id.name).cloned() {
|
let type_name = self.interner.resolve(id.name);
|
||||||
if let Some(const_val) = constants.get(&n.member) {
|
let member_name = self.interner.resolve(n.member);
|
||||||
let old_ctx = self.current_type_context.replace(id.name.clone());
|
if let Some(constants) = self.type_constants.get(type_name).cloned() {
|
||||||
|
if let Some(const_val) = constants.get(member_name) {
|
||||||
|
let old_ctx = self.current_type_context.replace(type_name.to_string());
|
||||||
let res = self.lower_node(const_val);
|
let res = self.lower_node(const_val);
|
||||||
self.current_type_context = old_ctx;
|
self.current_type_context = old_ctx;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if id.name == "Color" {
|
if type_name == "Color" {
|
||||||
let val = match n.member.as_str() {
|
let val = match member_name {
|
||||||
"BLACK" => 0x0000,
|
"BLACK" => 0x0000,
|
||||||
"WHITE" => 0xFFFF,
|
"WHITE" => 0xFFFF,
|
||||||
"RED" => 0xF800,
|
"RED" => 0xF800,
|
||||||
@ -578,18 +609,21 @@ impl<'a> Lowerer<'a> {
|
|||||||
fn resolve_member_access(&self, n: &MemberAccessNode) -> Option<(u32, Type)> {
|
fn resolve_member_access(&self, n: &MemberAccessNode) -> Option<(u32, Type)> {
|
||||||
match &*n.object {
|
match &*n.object {
|
||||||
Node::Ident(id) => {
|
Node::Ident(id) => {
|
||||||
let info = self.find_local(&id.name)?;
|
let name_str = self.interner.resolve(id.name);
|
||||||
|
let member_str = self.interner.resolve(n.member);
|
||||||
|
let info = self.find_local(name_str)?;
|
||||||
if let Type::Struct(sname) = &info.ty {
|
if let Type::Struct(sname) = &info.ty {
|
||||||
let offset = self.get_field_offset(sname, &n.member);
|
let offset = self.get_field_offset(sname, member_str);
|
||||||
let ty = self.get_field_type(sname, &n.member);
|
let ty = self.get_field_type(sname, member_str);
|
||||||
Some((info.slot + offset, ty))
|
Some((info.slot + offset, ty))
|
||||||
} else { None }
|
} else { None }
|
||||||
}
|
}
|
||||||
Node::MemberAccess(inner) => {
|
Node::MemberAccess(inner) => {
|
||||||
|
let member_str = self.interner.resolve(n.member);
|
||||||
let (base_slot, ty) = self.resolve_member_access(inner)?;
|
let (base_slot, ty) = self.resolve_member_access(inner)?;
|
||||||
if let Type::Struct(sname) = &ty {
|
if let Type::Struct(sname) = &ty {
|
||||||
let offset = self.get_field_offset(sname, &n.member);
|
let offset = self.get_field_offset(sname, member_str);
|
||||||
let final_ty = self.get_field_type(sname, &n.member);
|
let final_ty = self.get_field_type(sname, member_str);
|
||||||
Some((base_slot + offset, final_ty))
|
Some((base_slot + offset, final_ty))
|
||||||
} else { None }
|
} else { None }
|
||||||
}
|
}
|
||||||
@ -649,9 +683,10 @@ impl<'a> Lowerer<'a> {
|
|||||||
fn lower_call(&mut self, n: &CallNode) -> Result<(), ()> {
|
fn lower_call(&mut self, n: &CallNode) -> Result<(), ()> {
|
||||||
match &*n.callee {
|
match &*n.callee {
|
||||||
Node::Ident(id_node) => {
|
Node::Ident(id_node) => {
|
||||||
|
let callee_name = self.interner.resolve(id_node.name).to_string();
|
||||||
// 1. Check for constructor call: TypeName(...)
|
// 1. Check for constructor call: TypeName(...)
|
||||||
let ctor = self.struct_constructors.get(&id_node.name)
|
let ctor = self.struct_constructors.get(&callee_name)
|
||||||
.and_then(|ctors| ctors.get(&id_node.name))
|
.and_then(|ctors| ctors.get(&callee_name))
|
||||||
.cloned();
|
.cloned();
|
||||||
|
|
||||||
if let Some(ctor) = ctor {
|
if let Some(ctor) = ctor {
|
||||||
@ -660,7 +695,7 @@ impl<'a> Lowerer<'a> {
|
|||||||
|
|
||||||
if let Some(ctx) = &self.current_type_context {
|
if let Some(ctx) = &self.current_type_context {
|
||||||
let ctor = self.struct_constructors.get(ctx)
|
let ctor = self.struct_constructors.get(ctx)
|
||||||
.and_then(|ctors| ctors.get(&id_node.name))
|
.and_then(|ctors| ctors.get(&callee_name))
|
||||||
.cloned();
|
.cloned();
|
||||||
|
|
||||||
if let Some(ctor) = ctor {
|
if let Some(ctor) = ctor {
|
||||||
@ -671,10 +706,10 @@ impl<'a> Lowerer<'a> {
|
|||||||
for arg in &n.args {
|
for arg in &n.args {
|
||||||
self.lower_node(arg)?;
|
self.lower_node(arg)?;
|
||||||
}
|
}
|
||||||
if let Some(func_id) = self.function_ids.get(&id_node.name) {
|
if let Some(func_id) = self.function_ids.get(&callee_name) {
|
||||||
self.emit(InstrKind::Call(*func_id, n.args.len() as u32));
|
self.emit(InstrKind::Call(*func_id, n.args.len() as u32));
|
||||||
Ok(())
|
Ok(())
|
||||||
} else if let Some(sym) = self.imported_symbols.value_symbols.get(&id_node.name) {
|
} else if let Some(sym) = self.imported_symbols.value_symbols.get(id_node.name) {
|
||||||
if let Some(origin) = &sym.origin {
|
if let Some(origin) = &sym.origin {
|
||||||
if origin.starts_with('@') {
|
if origin.starts_with('@') {
|
||||||
// Format: @dep_alias:module_path
|
// Format: @dep_alias:module_path
|
||||||
@ -682,32 +717,52 @@ impl<'a> Lowerer<'a> {
|
|||||||
if parts.len() == 2 {
|
if parts.len() == 2 {
|
||||||
let dep_alias = parts[0].to_string();
|
let dep_alias = parts[0].to_string();
|
||||||
let module_path = parts[1].to_string();
|
let module_path = parts[1].to_string();
|
||||||
self.emit(InstrKind::ImportCall(dep_alias, module_path, sym.name.clone(), n.args.len() as u32));
|
self.emit(InstrKind::ImportCall(
|
||||||
|
dep_alias,
|
||||||
|
module_path,
|
||||||
|
self.interner.resolve(sym.name).to_string(),
|
||||||
|
n.args.len() as u32,
|
||||||
|
));
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.error("E_LOWER_UNSUPPORTED", format!("Calling symbol '{}' with origin {:?} is not supported yet in v0", id_node.name, sym.origin), id_node.span);
|
self.error(
|
||||||
|
"E_LOWER_UNSUPPORTED",
|
||||||
|
format!(
|
||||||
|
"Calling symbol '{}' with origin {:?} is not supported yet in v0",
|
||||||
|
callee_name,
|
||||||
|
sym.origin
|
||||||
|
),
|
||||||
|
id_node.span,
|
||||||
|
);
|
||||||
Err(())
|
Err(())
|
||||||
} else {
|
} else {
|
||||||
// Check for special built-in functions
|
// Check for special built-in functions
|
||||||
match id_node.name.as_str() {
|
match callee_name.as_str() {
|
||||||
"some" | "ok" | "err" => {
|
"some" | "ok" | "err" => {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.error("E_RESOLVE_UNDEFINED", format!("Undefined function '{}'", id_node.name), id_node.span);
|
self.error(
|
||||||
|
"E_RESOLVE_UNDEFINED",
|
||||||
|
format!("Undefined function '{}'", callee_name),
|
||||||
|
id_node.span,
|
||||||
|
);
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Node::MemberAccess(ma) => {
|
Node::MemberAccess(ma) => {
|
||||||
// Check if it's a constructor alias: TypeName.Alias(...)
|
// Check if it's a constructor alias: TypeName.Alias(...)
|
||||||
let ctor = if let Node::Ident(obj_id) = &*ma.object {
|
let ctor = if let Node::Ident(obj_id) = &*ma.object {
|
||||||
self.struct_constructors.get(&obj_id.name)
|
let obj_name = self.interner.resolve(obj_id.name);
|
||||||
.and_then(|ctors| ctors.get(&ma.member))
|
let member_name = self.interner.resolve(ma.member);
|
||||||
|
self.struct_constructors
|
||||||
|
.get(obj_name)
|
||||||
|
.and_then(|ctors| ctors.get(member_name))
|
||||||
.cloned()
|
.cloned()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -718,9 +773,11 @@ impl<'a> Lowerer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for Pad.any()
|
// Check for Pad.any()
|
||||||
if ma.member == "any" {
|
let member_name = self.interner.resolve(ma.member);
|
||||||
|
if member_name == "any" {
|
||||||
if let Node::Ident(obj_id) = &*ma.object {
|
if let Node::Ident(obj_id) = &*ma.object {
|
||||||
if let Some(info) = self.find_local(&obj_id.name) {
|
let obj_name = self.interner.resolve(obj_id.name);
|
||||||
|
if let Some(info) = self.find_local(obj_name) {
|
||||||
if let Type::Struct(sname) = &info.ty {
|
if let Type::Struct(sname) = &info.ty {
|
||||||
if sname == "Pad" {
|
if sname == "Pad" {
|
||||||
self.lower_pad_any(info.slot);
|
self.lower_pad_any(info.slot);
|
||||||
@ -733,19 +790,20 @@ impl<'a> Lowerer<'a> {
|
|||||||
|
|
||||||
// Host contract static calls: Contract.method(...)
|
// Host contract static calls: Contract.method(...)
|
||||||
if let Node::Ident(obj_id) = &*ma.object {
|
if let Node::Ident(obj_id) = &*ma.object {
|
||||||
let is_local = self.find_local(&obj_id.name).is_some();
|
let obj_name = self.interner.resolve(obj_id.name);
|
||||||
|
let is_local = self.find_local(obj_name).is_some();
|
||||||
|
|
||||||
if !is_local {
|
if !is_local {
|
||||||
// Check type symbol (current or imported) for a host contract
|
// Check type symbol (current or imported) for a host contract
|
||||||
let sym_opt = self.module_symbols.type_symbols.get(&obj_id.name)
|
let sym_opt = self.module_symbols.type_symbols.get(obj_id.name)
|
||||||
.or_else(|| self.imported_symbols.type_symbols.get(&obj_id.name));
|
.or_else(|| self.imported_symbols.type_symbols.get(obj_id.name));
|
||||||
if let Some(sym) = sym_opt {
|
if let Some(sym) = sym_opt {
|
||||||
if sym.kind == SymbolKind::Contract && sym.is_host {
|
if sym.kind == SymbolKind::Contract && sym.is_host {
|
||||||
// Lower arguments first to avoid borrowing conflicts
|
// Lower arguments first to avoid borrowing conflicts
|
||||||
for arg in &n.args {
|
for arg in &n.args {
|
||||||
self.lower_node(arg)?;
|
self.lower_node(arg)?;
|
||||||
}
|
}
|
||||||
if let Some(method) = self.contract_registry.get_method(&obj_id.name, &ma.member) {
|
if let Some(method) = self.contract_registry.get_method(obj_name, member_name) {
|
||||||
let id = method.id;
|
let id = method.id;
|
||||||
let return_slots = if matches!(method.return_type, PbsType::Void) { 0 } else { 1 };
|
let return_slots = if matches!(method.return_type, PbsType::Void) { 0 } else { 1 };
|
||||||
self.emit(InstrKind::HostCall(id, return_slots));
|
self.emit(InstrKind::HostCall(id, return_slots));
|
||||||
@ -757,15 +815,15 @@ impl<'a> Lowerer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for .raw()
|
// Check for .raw()
|
||||||
if ma.member == "raw" {
|
if member_name == "raw" {
|
||||||
self.lower_node(&ma.object)?;
|
self.lower_node(&ma.object)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for Color.rgb
|
// Check for Color.rgb
|
||||||
if ma.member == "rgb" {
|
if member_name == "rgb" {
|
||||||
if let Node::Ident(obj_id) = &*ma.object {
|
if let Node::Ident(obj_id) = &*ma.object {
|
||||||
if obj_id.name == "Color" {
|
if self.interner.resolve(obj_id.name) == "Color" {
|
||||||
if n.args.len() == 3 {
|
if n.args.len() == 3 {
|
||||||
// Try to get literal values for r, g, b
|
// Try to get literal values for r, g, b
|
||||||
let mut literals = Vec::new();
|
let mut literals = Vec::new();
|
||||||
@ -798,20 +856,25 @@ impl<'a> Lowerer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Node::Ident(obj_id) = &*ma.object {
|
if let Node::Ident(obj_id) = &*ma.object {
|
||||||
let is_host_contract = self.module_symbols.type_symbols.get(&obj_id.name)
|
let obj_name = self.interner.resolve(obj_id.name);
|
||||||
|
let is_host_contract = self.module_symbols.type_symbols.get(obj_id.name)
|
||||||
.map(|sym| sym.kind == SymbolKind::Contract && sym.is_host)
|
.map(|sym| sym.kind == SymbolKind::Contract && sym.is_host)
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
|
|
||||||
let is_shadowed = self.find_local(&obj_id.name).is_some();
|
let is_shadowed = self.find_local(obj_name).is_some();
|
||||||
|
|
||||||
if is_host_contract && !is_shadowed {
|
if is_host_contract && !is_shadowed {
|
||||||
if let Some(method) = self.contract_registry.get_method(&obj_id.name, &ma.member) {
|
if let Some(method) = self.contract_registry.get_method(obj_name, member_name) {
|
||||||
let ir_ty = self.convert_pbs_type(&method.return_type);
|
let ir_ty = self.convert_pbs_type(&method.return_type);
|
||||||
let return_slots = self.get_type_slots(&ir_ty);
|
let return_slots = self.get_type_slots(&ir_ty);
|
||||||
self.emit(InstrKind::HostCall(method.id, return_slots));
|
self.emit(InstrKind::HostCall(method.id, return_slots));
|
||||||
return Ok(());
|
return Ok(());
|
||||||
} else {
|
} else {
|
||||||
self.error("E_RESOLVE_UNDEFINED", format!("Undefined contract member '{}.{}'", obj_id.name, ma.member), ma.span);
|
self.error(
|
||||||
|
"E_RESOLVE_UNDEFINED",
|
||||||
|
format!("Undefined contract member '{}.{}'", obj_name, member_name),
|
||||||
|
ma.span,
|
||||||
|
);
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -834,7 +897,7 @@ impl<'a> Lowerer<'a> {
|
|||||||
let mut param_map = HashMap::new();
|
let mut param_map = HashMap::new();
|
||||||
for (i, param) in ctor.params.iter().enumerate() {
|
for (i, param) in ctor.params.iter().enumerate() {
|
||||||
if i < args.len() {
|
if i < args.len() {
|
||||||
param_map.insert(param.name.clone(), args[i].clone());
|
param_map.insert(self.interner.resolve(param.name).to_string(), args[i].clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -848,7 +911,7 @@ impl<'a> Lowerer<'a> {
|
|||||||
fn substitute_node(&self, node: &Node, param_map: &HashMap<String, Node>) -> Node {
|
fn substitute_node(&self, node: &Node, param_map: &HashMap<String, Node>) -> Node {
|
||||||
match node {
|
match node {
|
||||||
Node::Ident(id) => {
|
Node::Ident(id) => {
|
||||||
if let Some(arg) = param_map.get(&id.name) {
|
if let Some(arg) = param_map.get(self.interner.resolve(id.name)) {
|
||||||
arg.clone()
|
arg.clone()
|
||||||
} else {
|
} else {
|
||||||
node.clone()
|
node.clone()
|
||||||
@ -961,17 +1024,18 @@ impl<'a> Lowerer<'a> {
|
|||||||
|
|
||||||
fn lower_type_node(&mut self, node: &Node) -> Type {
|
fn lower_type_node(&mut self, node: &Node) -> Type {
|
||||||
match node {
|
match node {
|
||||||
Node::TypeName(n) => match n.name.as_str() {
|
Node::TypeName(n) => match self.interner.resolve(n.name) {
|
||||||
"int" => Type::Int,
|
"int" => Type::Int,
|
||||||
"bounded" => Type::Bounded,
|
"bounded" => Type::Bounded,
|
||||||
"float" => Type::Float,
|
"float" => Type::Float,
|
||||||
"bool" => Type::Bool,
|
"bool" => Type::Bool,
|
||||||
"string" => Type::String,
|
"string" => Type::String,
|
||||||
"void" => Type::Void,
|
"void" => Type::Void,
|
||||||
_ => Type::Struct(n.name.clone()),
|
_ => Type::Struct(self.interner.resolve(n.name).to_string()),
|
||||||
},
|
},
|
||||||
Node::TypeApp(ta) => {
|
Node::TypeApp(ta) => {
|
||||||
if ta.base == "array" {
|
let base_name = self.interner.resolve(ta.base);
|
||||||
|
if base_name == "array" {
|
||||||
let elem_ty = self.lower_type_node(&ta.args[0]);
|
let elem_ty = self.lower_type_node(&ta.args[0]);
|
||||||
let size = if ta.args.len() > 1 {
|
let size = if ta.args.len() > 1 {
|
||||||
if let Node::IntLit(il) = &ta.args[1] {
|
if let Node::IntLit(il) = &ta.args[1] {
|
||||||
@ -983,15 +1047,15 @@ impl<'a> Lowerer<'a> {
|
|||||||
0
|
0
|
||||||
};
|
};
|
||||||
Type::Array(Box::new(elem_ty), size)
|
Type::Array(Box::new(elem_ty), size)
|
||||||
} else if ta.base == "optional" {
|
} else if base_name == "optional" {
|
||||||
Type::Optional(Box::new(self.lower_type_node(&ta.args[0])))
|
Type::Optional(Box::new(self.lower_type_node(&ta.args[0])))
|
||||||
} else if ta.base == "result" {
|
} else if base_name == "result" {
|
||||||
Type::Result(
|
Type::Result(
|
||||||
Box::new(self.lower_type_node(&ta.args[0])),
|
Box::new(self.lower_type_node(&ta.args[0])),
|
||||||
Box::new(self.lower_type_node(&ta.args[1]))
|
Box::new(self.lower_type_node(&ta.args[1]))
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Type::Struct(format!("{}<{}>", ta.base, ta.args.len()))
|
Type::Struct(format!("{}<{}>", base_name, ta.args.len()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Type::Void,
|
_ => Type::Void,
|
||||||
@ -1126,6 +1190,7 @@ mod tests {
|
|||||||
use crate::frontends::pbs::parser::Parser;
|
use crate::frontends::pbs::parser::Parser;
|
||||||
use crate::frontends::pbs::symbols::ModuleSymbols;
|
use crate::frontends::pbs::symbols::ModuleSymbols;
|
||||||
use crate::ir_core;
|
use crate::ir_core;
|
||||||
|
use prometeu_analysis::NameInterner;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_basic_lowering() {
|
fn test_basic_lowering() {
|
||||||
@ -1137,14 +1202,16 @@ mod tests {
|
|||||||
let x = add(10, 20);
|
let x = add(10, 20);
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
let mut parser = Parser::new(code, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(code, 0, &mut interner);
|
||||||
let ast = parser.parse_file().expect("Failed to parse");
|
let ast = parser.parse_file().expect("Failed to parse");
|
||||||
|
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
||||||
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
||||||
|
|
||||||
let imported = ModuleSymbols::new(); let lowerer = Lowerer::new(&module_symbols, &imported);
|
let imported = ModuleSymbols::new();
|
||||||
|
let lowerer = Lowerer::new(&module_symbols, &imported, &interner);
|
||||||
let program = lowerer.lower_file(&ast, "test").expect("Lowering failed");
|
let program = lowerer.lower_file(&ast, "test").expect("Lowering failed");
|
||||||
|
|
||||||
// Verify program structure
|
// Verify program structure
|
||||||
@ -1174,14 +1241,16 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
let mut parser = Parser::new(code, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(code, 0, &mut interner);
|
||||||
let ast = parser.parse_file().expect("Failed to parse");
|
let ast = parser.parse_file().expect("Failed to parse");
|
||||||
|
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
||||||
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
||||||
|
|
||||||
let imported = ModuleSymbols::new(); let lowerer = Lowerer::new(&module_symbols, &imported);
|
let imported = ModuleSymbols::new();
|
||||||
|
let lowerer = Lowerer::new(&module_symbols, &imported, &interner);
|
||||||
let program = lowerer.lower_file(&ast, "test").expect("Lowering failed");
|
let program = lowerer.lower_file(&ast, "test").expect("Lowering failed");
|
||||||
|
|
||||||
let max_func = &program.modules[0].functions[0];
|
let max_func = &program.modules[0].functions[0];
|
||||||
@ -1199,14 +1268,16 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
let mut parser = Parser::new(code, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(code, 0, &mut interner);
|
||||||
let ast = parser.parse_file().expect("Failed to parse");
|
let ast = parser.parse_file().expect("Failed to parse");
|
||||||
|
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
||||||
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
||||||
|
|
||||||
let imported = ModuleSymbols::new(); let lowerer = Lowerer::new(&module_symbols, &imported);
|
let imported = ModuleSymbols::new();
|
||||||
|
let lowerer = Lowerer::new(&module_symbols, &imported, &interner);
|
||||||
let program = lowerer.lower_file(&ast, "test").expect("Lowering failed");
|
let program = lowerer.lower_file(&ast, "test").expect("Lowering failed");
|
||||||
|
|
||||||
let func = &program.modules[0].functions[0];
|
let func = &program.modules[0].functions[0];
|
||||||
@ -1227,14 +1298,16 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
let mut parser = Parser::new(code, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(code, 0, &mut interner);
|
||||||
let ast = parser.parse_file().expect("Failed to parse");
|
let ast = parser.parse_file().expect("Failed to parse");
|
||||||
|
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let (type_symbols, value_symbols) = collector.collect(&ast).unwrap();
|
let (type_symbols, value_symbols) = collector.collect(&ast).unwrap();
|
||||||
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
||||||
|
|
||||||
let imported = ModuleSymbols::new(); let lowerer = Lowerer::new(&module_symbols, &imported);
|
let imported = ModuleSymbols::new();
|
||||||
|
let lowerer = Lowerer::new(&module_symbols, &imported, &interner);
|
||||||
let program = lowerer.lower_file(&ast, "test").expect("Lowering failed");
|
let program = lowerer.lower_file(&ast, "test").expect("Lowering failed");
|
||||||
|
|
||||||
let json = serde_json::to_string_pretty(&program).unwrap();
|
let json = serde_json::to_string_pretty(&program).unwrap();
|
||||||
@ -1268,14 +1341,16 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
let mut parser = Parser::new(code, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(code, 0, &mut interner);
|
||||||
let ast = parser.parse_file().expect("Failed to parse");
|
let ast = parser.parse_file().expect("Failed to parse");
|
||||||
|
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
||||||
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
||||||
|
|
||||||
let imported = ModuleSymbols::new(); let lowerer = Lowerer::new(&module_symbols, &imported);
|
let imported = ModuleSymbols::new();
|
||||||
|
let lowerer = Lowerer::new(&module_symbols, &imported, &interner);
|
||||||
let program = lowerer.lower_file(&ast, "test").expect("Lowering failed");
|
let program = lowerer.lower_file(&ast, "test").expect("Lowering failed");
|
||||||
|
|
||||||
let func = &program.modules[0].functions[0];
|
let func = &program.modules[0].functions[0];
|
||||||
@ -1302,14 +1377,16 @@ mod tests {
|
|||||||
Log.write(2, \"Hello\");
|
Log.write(2, \"Hello\");
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
let mut parser = Parser::new(code, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(code, 0, &mut interner);
|
||||||
let ast = parser.parse_file().expect("Failed to parse");
|
let ast = parser.parse_file().expect("Failed to parse");
|
||||||
|
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
||||||
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
||||||
|
|
||||||
let imported = ModuleSymbols::new(); let lowerer = Lowerer::new(&module_symbols, &imported);
|
let imported = ModuleSymbols::new();
|
||||||
|
let lowerer = Lowerer::new(&module_symbols, &imported, &interner);
|
||||||
let program = lowerer.lower_file(&ast, "test").expect("Lowering failed");
|
let program = lowerer.lower_file(&ast, "test").expect("Lowering failed");
|
||||||
|
|
||||||
let func = &program.modules[0].functions[0];
|
let func = &program.modules[0].functions[0];
|
||||||
@ -1329,14 +1406,16 @@ mod tests {
|
|||||||
Gfx.clear(0);
|
Gfx.clear(0);
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
let mut parser = Parser::new(code, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(code, 0, &mut interner);
|
||||||
let ast = parser.parse_file().expect("Failed to parse");
|
let ast = parser.parse_file().expect("Failed to parse");
|
||||||
|
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
||||||
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
||||||
|
|
||||||
let imported = ModuleSymbols::new(); let lowerer = Lowerer::new(&module_symbols, &imported);
|
let imported = ModuleSymbols::new();
|
||||||
|
let lowerer = Lowerer::new(&module_symbols, &imported, &interner);
|
||||||
let result = lowerer.lower_file(&ast, "test");
|
let result = lowerer.lower_file(&ast, "test");
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
@ -1353,14 +1432,16 @@ mod tests {
|
|||||||
Gfx.clear(0);
|
Gfx.clear(0);
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
let mut parser = Parser::new(code, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(code, 0, &mut interner);
|
||||||
let ast = parser.parse_file().expect("Failed to parse");
|
let ast = parser.parse_file().expect("Failed to parse");
|
||||||
|
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
||||||
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
||||||
|
|
||||||
let imported = ModuleSymbols::new(); let lowerer = Lowerer::new(&module_symbols, &imported);
|
let imported = ModuleSymbols::new();
|
||||||
|
let lowerer = Lowerer::new(&module_symbols, &imported, &interner);
|
||||||
let result = lowerer.lower_file(&ast, "test");
|
let result = lowerer.lower_file(&ast, "test");
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
@ -1376,14 +1457,16 @@ mod tests {
|
|||||||
Gfx.invalidMethod(0);
|
Gfx.invalidMethod(0);
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
let mut parser = Parser::new(code, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(code, 0, &mut interner);
|
||||||
let ast = parser.parse_file().expect("Failed to parse");
|
let ast = parser.parse_file().expect("Failed to parse");
|
||||||
|
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
||||||
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
||||||
|
|
||||||
let imported = ModuleSymbols::new(); let lowerer = Lowerer::new(&module_symbols, &imported);
|
let imported = ModuleSymbols::new();
|
||||||
|
let lowerer = Lowerer::new(&module_symbols, &imported, &interner);
|
||||||
let result = lowerer.lower_file(&ast, "test");
|
let result = lowerer.lower_file(&ast, "test");
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
@ -1399,14 +1482,16 @@ mod tests {
|
|||||||
let v = alloc Vec3;
|
let v = alloc Vec3;
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
let mut parser = Parser::new(code, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(code, 0, &mut interner);
|
||||||
let ast = parser.parse_file().expect("Failed to parse");
|
let ast = parser.parse_file().expect("Failed to parse");
|
||||||
|
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
||||||
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
||||||
|
|
||||||
let imported = ModuleSymbols::new(); let lowerer = Lowerer::new(&module_symbols, &imported);
|
let imported = ModuleSymbols::new();
|
||||||
|
let lowerer = Lowerer::new(&module_symbols, &imported, &interner);
|
||||||
let program = lowerer.lower_file(&ast, "test").expect("Lowering failed");
|
let program = lowerer.lower_file(&ast, "test").expect("Lowering failed");
|
||||||
|
|
||||||
let func = &program.modules[0].functions[0];
|
let func = &program.modules[0].functions[0];
|
||||||
@ -1431,14 +1516,16 @@ mod tests {
|
|||||||
let a = alloc array<int>[10b];
|
let a = alloc array<int>[10b];
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
let mut parser = Parser::new(code, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(code, 0, &mut interner);
|
||||||
let ast = parser.parse_file().expect("Failed to parse");
|
let ast = parser.parse_file().expect("Failed to parse");
|
||||||
|
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
||||||
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
||||||
|
|
||||||
let imported = ModuleSymbols::new(); let lowerer = Lowerer::new(&module_symbols, &imported);
|
let imported = ModuleSymbols::new();
|
||||||
|
let lowerer = Lowerer::new(&module_symbols, &imported, &interner);
|
||||||
let program = lowerer.lower_file(&ast, "test").expect("Lowering failed");
|
let program = lowerer.lower_file(&ast, "test").expect("Lowering failed");
|
||||||
|
|
||||||
let func = &program.modules[0].functions[0];
|
let func = &program.modules[0].functions[0];
|
||||||
@ -1463,14 +1550,16 @@ mod tests {
|
|||||||
let x = alloc int;
|
let x = alloc int;
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
let mut parser = Parser::new(code, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(code, 0, &mut interner);
|
||||||
let ast = parser.parse_file().expect("Failed to parse");
|
let ast = parser.parse_file().expect("Failed to parse");
|
||||||
|
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
||||||
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
||||||
|
|
||||||
let imported = ModuleSymbols::new(); let lowerer = Lowerer::new(&module_symbols, &imported);
|
let imported = ModuleSymbols::new();
|
||||||
|
let lowerer = Lowerer::new(&module_symbols, &imported, &interner);
|
||||||
let program = lowerer.lower_file(&ast, "test").expect("Lowering failed");
|
let program = lowerer.lower_file(&ast, "test").expect("Lowering failed");
|
||||||
|
|
||||||
let func = &program.modules[0].functions[0];
|
let func = &program.modules[0].functions[0];
|
||||||
@ -1495,14 +1584,16 @@ mod tests {
|
|||||||
missing_func();
|
missing_func();
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
let mut parser = Parser::new(code, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(code, 0, &mut interner);
|
||||||
let ast = parser.parse_file().expect("Failed to parse");
|
let ast = parser.parse_file().expect("Failed to parse");
|
||||||
|
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
||||||
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
||||||
|
|
||||||
let imported = ModuleSymbols::new(); let lowerer = Lowerer::new(&module_symbols, &imported);
|
let imported = ModuleSymbols::new();
|
||||||
|
let lowerer = Lowerer::new(&module_symbols, &imported, &interner);
|
||||||
let result = lowerer.lower_file(&ast, "test");
|
let result = lowerer.lower_file(&ast, "test");
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
@ -1518,14 +1609,16 @@ mod tests {
|
|||||||
let x = undefined_var;
|
let x = undefined_var;
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
let mut parser = Parser::new(code, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(code, 0, &mut interner);
|
||||||
let ast = parser.parse_file().expect("Failed to parse");
|
let ast = parser.parse_file().expect("Failed to parse");
|
||||||
|
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
||||||
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
||||||
|
|
||||||
let imported = ModuleSymbols::new(); let lowerer = Lowerer::new(&module_symbols, &imported);
|
let imported = ModuleSymbols::new();
|
||||||
|
let lowerer = Lowerer::new(&module_symbols, &imported, &interner);
|
||||||
let result = lowerer.lower_file(&ast, "test");
|
let result = lowerer.lower_file(&ast, "test");
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
|
|||||||
@ -23,6 +23,7 @@ use crate::common::files::FileManager;
|
|||||||
use crate::frontends::Frontend;
|
use crate::frontends::Frontend;
|
||||||
use crate::ir_vm;
|
use crate::ir_vm;
|
||||||
use crate::lowering::core_to_vm;
|
use crate::lowering::core_to_vm;
|
||||||
|
use prometeu_analysis::NameInterner;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
pub struct PbsFrontend;
|
pub struct PbsFrontend;
|
||||||
@ -42,10 +43,11 @@ impl Frontend for PbsFrontend {
|
|||||||
})?;
|
})?;
|
||||||
let file_id = file_manager.add(entry.to_path_buf(), source.clone());
|
let file_id = file_manager.add(entry.to_path_buf(), source.clone());
|
||||||
|
|
||||||
let mut parser = parser::Parser::new(&source, file_id);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = parser::Parser::new(&source, file_id, &mut interner);
|
||||||
let ast = parser.parse_file()?;
|
let ast = parser.parse_file()?;
|
||||||
|
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let (type_symbols, value_symbols) = collector.collect(&ast)?;
|
let (type_symbols, value_symbols) = collector.collect(&ast)?;
|
||||||
let mut module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
let mut module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
||||||
|
|
||||||
@ -54,15 +56,15 @@ impl Frontend for PbsFrontend {
|
|||||||
fn get_module_symbols(&self, _path: &str) -> Option<&ModuleSymbols> { None }
|
fn get_module_symbols(&self, _path: &str) -> Option<&ModuleSymbols> { None }
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut resolver = Resolver::new(&module_symbols, &EmptyProvider);
|
let mut resolver = Resolver::new(&module_symbols, &EmptyProvider, &interner);
|
||||||
resolver.resolve(&ast)?;
|
resolver.resolve(&ast)?;
|
||||||
let imported_symbols = resolver.imported_symbols;
|
let imported_symbols = resolver.imported_symbols;
|
||||||
|
|
||||||
let mut typechecker = TypeChecker::new(&mut module_symbols, &imported_symbols, &EmptyProvider);
|
let mut typechecker = TypeChecker::new(&mut module_symbols, &imported_symbols, &EmptyProvider, &interner);
|
||||||
typechecker.check(&ast)?;
|
typechecker.check(&ast)?;
|
||||||
|
|
||||||
// Lower to Core IR
|
// Lower to Core IR
|
||||||
let lowerer = Lowerer::new(&module_symbols, &imported_symbols);
|
let lowerer = Lowerer::new(&module_symbols, &imported_symbols, &interner);
|
||||||
let module_name = entry.file_stem().unwrap().to_string_lossy();
|
let module_name = entry.file_stem().unwrap().to_string_lossy();
|
||||||
let core_program = lowerer.lower_file(&ast, &module_name)?;
|
let core_program = lowerer.lower_file(&ast, &module_name)?;
|
||||||
|
|
||||||
|
|||||||
@ -3,16 +3,29 @@ use crate::common::spans::Span;
|
|||||||
use crate::frontends::pbs::ast::*;
|
use crate::frontends::pbs::ast::*;
|
||||||
use crate::frontends::pbs::lexer::Lexer;
|
use crate::frontends::pbs::lexer::Lexer;
|
||||||
use crate::frontends::pbs::token::{Token, TokenKind};
|
use crate::frontends::pbs::token::{Token, TokenKind};
|
||||||
|
use prometeu_analysis::{NameId, NameInterner};
|
||||||
|
|
||||||
pub struct Parser {
|
pub struct Parser<'a> {
|
||||||
tokens: Vec<Token>,
|
tokens: Vec<Token>,
|
||||||
pos: usize,
|
pos: usize,
|
||||||
file_id: usize,
|
file_id: usize,
|
||||||
errors: Vec<Diagnostic>,
|
errors: Vec<Diagnostic>,
|
||||||
|
interner: &'a mut NameInterner,
|
||||||
|
builtin_none: NameId,
|
||||||
|
builtin_some: NameId,
|
||||||
|
builtin_ok: NameId,
|
||||||
|
builtin_err: NameId,
|
||||||
|
builtin_true: NameId,
|
||||||
|
builtin_false: NameId,
|
||||||
|
builtin_void: NameId,
|
||||||
|
builtin_array: NameId,
|
||||||
|
builtin_optional: NameId,
|
||||||
|
builtin_result: NameId,
|
||||||
|
builtin_bounded: NameId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parser {
|
impl<'a> Parser<'a> {
|
||||||
pub fn new(source: &str, file_id: usize) -> Self {
|
pub fn new(source: &str, file_id: usize, interner: &'a mut NameInterner) -> Self {
|
||||||
let mut lexer = Lexer::new(source, file_id);
|
let mut lexer = Lexer::new(source, file_id);
|
||||||
let mut tokens = Vec::new();
|
let mut tokens = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
@ -24,11 +37,35 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let builtin_none = interner.intern("none");
|
||||||
|
let builtin_some = interner.intern("some");
|
||||||
|
let builtin_ok = interner.intern("ok");
|
||||||
|
let builtin_err = interner.intern("err");
|
||||||
|
let builtin_true = interner.intern("true");
|
||||||
|
let builtin_false = interner.intern("false");
|
||||||
|
let builtin_void = interner.intern("void");
|
||||||
|
let builtin_array = interner.intern("array");
|
||||||
|
let builtin_optional = interner.intern("optional");
|
||||||
|
let builtin_result = interner.intern("result");
|
||||||
|
let builtin_bounded = interner.intern("bounded");
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
tokens,
|
tokens,
|
||||||
pos: 0,
|
pos: 0,
|
||||||
file_id,
|
file_id,
|
||||||
errors: Vec::new(),
|
errors: Vec::new(),
|
||||||
|
interner,
|
||||||
|
builtin_none,
|
||||||
|
builtin_some,
|
||||||
|
builtin_ok,
|
||||||
|
builtin_err,
|
||||||
|
builtin_true,
|
||||||
|
builtin_false,
|
||||||
|
builtin_void,
|
||||||
|
builtin_array,
|
||||||
|
builtin_optional,
|
||||||
|
builtin_result,
|
||||||
|
builtin_bounded,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,12 +149,12 @@ impl Parser {
|
|||||||
if self.peek().kind == TokenKind::OpenBrace {
|
if self.peek().kind == TokenKind::OpenBrace {
|
||||||
self.advance(); // {
|
self.advance(); // {
|
||||||
loop {
|
loop {
|
||||||
if let TokenKind::Identifier(ref name) = self.peek().kind {
|
let name = match self.peek().kind.clone() {
|
||||||
path.push(name.clone());
|
TokenKind::Identifier(name) => name,
|
||||||
|
_ => return Err(self.error("Expected identifier in import spec")),
|
||||||
|
};
|
||||||
self.advance();
|
self.advance();
|
||||||
} else {
|
path.push(self.interner.intern(&name));
|
||||||
return Err(self.error("Expected identifier in import spec"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.peek().kind == TokenKind::Comma {
|
if self.peek().kind == TokenKind::Comma {
|
||||||
self.advance();
|
self.advance();
|
||||||
@ -130,12 +167,12 @@ impl Parser {
|
|||||||
self.consume(TokenKind::CloseBrace)?;
|
self.consume(TokenKind::CloseBrace)?;
|
||||||
} else {
|
} else {
|
||||||
loop {
|
loop {
|
||||||
if let TokenKind::Identifier(ref name) = self.peek().kind {
|
let name = match self.peek().kind.clone() {
|
||||||
path.push(name.clone());
|
TokenKind::Identifier(name) => name,
|
||||||
|
_ => return Err(self.error("Expected identifier in import spec")),
|
||||||
|
};
|
||||||
self.advance();
|
self.advance();
|
||||||
} else {
|
path.push(self.interner.intern(&name));
|
||||||
return Err(self.error("Expected identifier in import spec"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.peek().kind == TokenKind::Dot {
|
if self.peek().kind == TokenKind::Dot {
|
||||||
self.advance();
|
self.advance();
|
||||||
@ -227,7 +264,7 @@ impl Parser {
|
|||||||
} else {
|
} else {
|
||||||
Box::new(Node::TypeName(TypeNameNode {
|
Box::new(Node::TypeName(TypeNameNode {
|
||||||
span: Span::new(self.file_id, 0, 0), // Placeholder for void
|
span: Span::new(self.file_id, 0, 0), // Placeholder for void
|
||||||
name: "void".to_string(),
|
name: self.builtin_void,
|
||||||
}))
|
}))
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -413,35 +450,35 @@ impl Parser {
|
|||||||
let name = match id_tok.kind {
|
let name = match id_tok.kind {
|
||||||
TokenKind::Identifier(ref s) => {
|
TokenKind::Identifier(ref s) => {
|
||||||
self.advance();
|
self.advance();
|
||||||
s.clone()
|
self.interner.intern(s)
|
||||||
}
|
}
|
||||||
TokenKind::Optional => {
|
TokenKind::Optional => {
|
||||||
self.advance();
|
self.advance();
|
||||||
"optional".to_string()
|
self.builtin_optional
|
||||||
}
|
}
|
||||||
TokenKind::Result => {
|
TokenKind::Result => {
|
||||||
self.advance();
|
self.advance();
|
||||||
"result".to_string()
|
self.builtin_result
|
||||||
}
|
}
|
||||||
TokenKind::Bounded => {
|
TokenKind::Bounded => {
|
||||||
self.advance();
|
self.advance();
|
||||||
"bounded".to_string()
|
self.builtin_bounded
|
||||||
}
|
}
|
||||||
TokenKind::None => {
|
TokenKind::None => {
|
||||||
self.advance();
|
self.advance();
|
||||||
"none".to_string()
|
self.builtin_none
|
||||||
}
|
}
|
||||||
TokenKind::Some => {
|
TokenKind::Some => {
|
||||||
self.advance();
|
self.advance();
|
||||||
"some".to_string()
|
self.builtin_some
|
||||||
}
|
}
|
||||||
TokenKind::Ok => {
|
TokenKind::Ok => {
|
||||||
self.advance();
|
self.advance();
|
||||||
"ok".to_string()
|
self.builtin_ok
|
||||||
}
|
}
|
||||||
TokenKind::Err => {
|
TokenKind::Err => {
|
||||||
self.advance();
|
self.advance();
|
||||||
"err".to_string()
|
self.builtin_err
|
||||||
}
|
}
|
||||||
_ => return Err(self.error_with_code("Expected type name", Some("E_PARSE_EXPECTED_TOKEN"))),
|
_ => return Err(self.error_with_code("Expected type name", Some("E_PARSE_EXPECTED_TOKEN"))),
|
||||||
};
|
};
|
||||||
@ -491,7 +528,7 @@ impl Parser {
|
|||||||
// If base was "array", it already has T in args.
|
// If base was "array", it already has T in args.
|
||||||
// We can just add N to args.
|
// We can just add N to args.
|
||||||
match &mut node {
|
match &mut node {
|
||||||
Node::TypeApp(ta) if ta.base == "array" => {
|
Node::TypeApp(ta) if ta.base == self.builtin_array => {
|
||||||
ta.args.push(Node::IntLit(IntLitNode { span: size_tok.span, value: size as i64 }));
|
ta.args.push(Node::IntLit(IntLitNode { span: size_tok.span, value: size as i64 }));
|
||||||
ta.span = span;
|
ta.span = span;
|
||||||
}
|
}
|
||||||
@ -499,7 +536,7 @@ impl Parser {
|
|||||||
// Fallback for T[N] if we want to support it, but spec says array<T>[N]
|
// Fallback for T[N] if we want to support it, but spec says array<T>[N]
|
||||||
node = Node::TypeApp(TypeAppNode {
|
node = Node::TypeApp(TypeAppNode {
|
||||||
span,
|
span,
|
||||||
base: "array".to_string(),
|
base: self.builtin_array,
|
||||||
args: vec![node, Node::IntLit(IntLitNode { span: size_tok.span, value: size as i64 })],
|
args: vec![node, Node::IntLit(IntLitNode { span: size_tok.span, value: size as i64 })],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -673,6 +710,7 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
TokenKind::Identifier(name) => {
|
TokenKind::Identifier(name) => {
|
||||||
self.advance();
|
self.advance();
|
||||||
|
let name = self.interner.intern(&name);
|
||||||
let mut node = Node::Ident(IdentNode { span: tok.span, name });
|
let mut node = Node::Ident(IdentNode { span: tok.span, name });
|
||||||
loop {
|
loop {
|
||||||
if self.peek().kind == TokenKind::OpenParen {
|
if self.peek().kind == TokenKind::OpenParen {
|
||||||
@ -689,12 +727,12 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
TokenKind::None | TokenKind::Some | TokenKind::Ok | TokenKind::Err => {
|
TokenKind::None | TokenKind::Some | TokenKind::Ok | TokenKind::Err => {
|
||||||
let name = match tok.kind {
|
let name = match tok.kind {
|
||||||
TokenKind::None => "none",
|
TokenKind::None => self.builtin_none,
|
||||||
TokenKind::Some => "some",
|
TokenKind::Some => self.builtin_some,
|
||||||
TokenKind::Ok => "ok",
|
TokenKind::Ok => self.builtin_ok,
|
||||||
TokenKind::Err => "err",
|
TokenKind::Err => self.builtin_err,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}.to_string();
|
};
|
||||||
self.advance();
|
self.advance();
|
||||||
let mut node = Node::Ident(IdentNode { span: tok.span, name });
|
let mut node = Node::Ident(IdentNode { span: tok.span, name });
|
||||||
loop {
|
loop {
|
||||||
@ -887,40 +925,40 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expect_identifier(&mut self) -> Result<String, DiagnosticBundle> {
|
fn expect_identifier(&mut self) -> Result<NameId, DiagnosticBundle> {
|
||||||
let peeked_kind = self.peek().kind.clone();
|
let peeked_kind = self.peek().kind.clone();
|
||||||
match peeked_kind {
|
match peeked_kind {
|
||||||
TokenKind::Identifier(name) => {
|
TokenKind::Identifier(name) => {
|
||||||
self.advance();
|
self.advance();
|
||||||
Ok(name)
|
Ok(self.interner.intern(&name))
|
||||||
}
|
}
|
||||||
TokenKind::Optional => {
|
TokenKind::Optional => {
|
||||||
self.advance();
|
self.advance();
|
||||||
Ok("optional".to_string())
|
Ok(self.builtin_optional)
|
||||||
}
|
}
|
||||||
TokenKind::Result => {
|
TokenKind::Result => {
|
||||||
self.advance();
|
self.advance();
|
||||||
Ok("result".to_string())
|
Ok(self.builtin_result)
|
||||||
}
|
}
|
||||||
TokenKind::None => {
|
TokenKind::None => {
|
||||||
self.advance();
|
self.advance();
|
||||||
Ok("none".to_string())
|
Ok(self.builtin_none)
|
||||||
}
|
}
|
||||||
TokenKind::Some => {
|
TokenKind::Some => {
|
||||||
self.advance();
|
self.advance();
|
||||||
Ok("some".to_string())
|
Ok(self.builtin_some)
|
||||||
}
|
}
|
||||||
TokenKind::Ok => {
|
TokenKind::Ok => {
|
||||||
self.advance();
|
self.advance();
|
||||||
Ok("ok".to_string())
|
Ok(self.builtin_ok)
|
||||||
}
|
}
|
||||||
TokenKind::Err => {
|
TokenKind::Err => {
|
||||||
self.advance();
|
self.advance();
|
||||||
Ok("err".to_string())
|
Ok(self.builtin_err)
|
||||||
}
|
}
|
||||||
TokenKind::Bounded => {
|
TokenKind::Bounded => {
|
||||||
self.advance();
|
self.advance();
|
||||||
Ok("bounded".to_string())
|
Ok(self.builtin_bounded)
|
||||||
}
|
}
|
||||||
TokenKind::Invalid(msg) => {
|
TokenKind::Invalid(msg) => {
|
||||||
let code = if msg.contains("Unterminated string") {
|
let code = if msg.contains("Unterminated string") {
|
||||||
@ -1036,7 +1074,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_empty_file() {
|
fn test_parse_empty_file() {
|
||||||
let mut parser = Parser::new("", 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new("", 0, &mut interner);
|
||||||
let result = parser.parse_file().unwrap();
|
let result = parser.parse_file().unwrap();
|
||||||
assert_eq!(result.imports.len(), 0);
|
assert_eq!(result.imports.len(), 0);
|
||||||
assert_eq!(result.decls.len(), 0);
|
assert_eq!(result.decls.len(), 0);
|
||||||
@ -1048,14 +1087,16 @@ mod tests {
|
|||||||
import std.io from "std";
|
import std.io from "std";
|
||||||
import math from "./math.pbs";
|
import math from "./math.pbs";
|
||||||
"#;
|
"#;
|
||||||
let mut parser = Parser::new(source, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(source, 0, &mut interner);
|
||||||
let result = parser.parse_file().unwrap();
|
let result = parser.parse_file().unwrap();
|
||||||
assert_eq!(result.imports.len(), 2);
|
assert_eq!(result.imports.len(), 2);
|
||||||
|
|
||||||
if let Node::Import(ref imp) = result.imports[0] {
|
if let Node::Import(ref imp) = result.imports[0] {
|
||||||
assert_eq!(imp.from, "std");
|
assert_eq!(imp.from, "std");
|
||||||
if let Node::ImportSpec(ref spec) = *imp.spec {
|
if let Node::ImportSpec(ref spec) = *imp.spec {
|
||||||
assert_eq!(spec.path, vec!["std", "io"]);
|
let path: Vec<&str> = spec.path.iter().map(|id| interner.resolve(*id)).collect();
|
||||||
|
assert_eq!(path, vec!["std", "io"]);
|
||||||
} else { panic!("Expected ImportSpec"); }
|
} else { panic!("Expected ImportSpec"); }
|
||||||
} else { panic!("Expected Import"); }
|
} else { panic!("Expected Import"); }
|
||||||
}
|
}
|
||||||
@ -1067,15 +1108,16 @@ fn add(a: int, b: int): int {
|
|||||||
return a + b;
|
return a + b;
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let mut parser = Parser::new(source, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(source, 0, &mut interner);
|
||||||
let result = parser.parse_file().unwrap();
|
let result = parser.parse_file().unwrap();
|
||||||
assert_eq!(result.decls.len(), 1);
|
assert_eq!(result.decls.len(), 1);
|
||||||
|
|
||||||
if let Node::FnDecl(ref f) = result.decls[0] {
|
if let Node::FnDecl(ref f) = result.decls[0] {
|
||||||
assert_eq!(f.name, "add");
|
assert_eq!(interner.resolve(f.name), "add");
|
||||||
assert_eq!(f.params.len(), 2);
|
assert_eq!(f.params.len(), 2);
|
||||||
assert_eq!(f.params[0].name, "a");
|
assert_eq!(interner.resolve(f.params[0].name), "a");
|
||||||
assert_eq!(f.params[1].name, "b");
|
assert_eq!(interner.resolve(f.params[1].name), "b");
|
||||||
} else { panic!("Expected FnDecl"); }
|
} else { panic!("Expected FnDecl"); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1087,12 +1129,13 @@ pub declare struct Point {
|
|||||||
y: int
|
y: int
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let mut parser = Parser::new(source, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(source, 0, &mut interner);
|
||||||
let result = parser.parse_file().unwrap();
|
let result = parser.parse_file().unwrap();
|
||||||
assert_eq!(result.decls.len(), 1);
|
assert_eq!(result.decls.len(), 1);
|
||||||
|
|
||||||
if let Node::TypeDecl(ref t) = result.decls[0] {
|
if let Node::TypeDecl(ref t) = result.decls[0] {
|
||||||
assert_eq!(t.name, "Point");
|
assert_eq!(interner.resolve(t.name), "Point");
|
||||||
assert_eq!(t.type_kind, "struct");
|
assert_eq!(t.type_kind, "struct");
|
||||||
assert_eq!(t.vis, Some("pub".to_string()));
|
assert_eq!(t.vis, Some("pub".to_string()));
|
||||||
} else { panic!("Expected TypeDecl"); }
|
} else { panic!("Expected TypeDecl"); }
|
||||||
@ -1106,12 +1149,13 @@ pub service Audio {
|
|||||||
fn stop(): bool;
|
fn stop(): bool;
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let mut parser = Parser::new(source, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(source, 0, &mut interner);
|
||||||
let result = parser.parse_file().unwrap();
|
let result = parser.parse_file().unwrap();
|
||||||
assert_eq!(result.decls.len(), 1);
|
assert_eq!(result.decls.len(), 1);
|
||||||
|
|
||||||
if let Node::ServiceDecl(ref s) = result.decls[0] {
|
if let Node::ServiceDecl(ref s) = result.decls[0] {
|
||||||
assert_eq!(s.name, "Audio");
|
assert_eq!(interner.resolve(s.name), "Audio");
|
||||||
assert_eq!(s.members.len(), 2);
|
assert_eq!(s.members.len(), 2);
|
||||||
} else { panic!("Expected ServiceDecl"); }
|
} else { panic!("Expected ServiceDecl"); }
|
||||||
}
|
}
|
||||||
@ -1125,7 +1169,8 @@ fn main() {
|
|||||||
foo(x, y);
|
foo(x, y);
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let mut parser = Parser::new(source, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(source, 0, &mut interner);
|
||||||
let result = parser.parse_file().unwrap();
|
let result = parser.parse_file().unwrap();
|
||||||
assert_eq!(result.decls.len(), 1);
|
assert_eq!(result.decls.len(), 1);
|
||||||
}
|
}
|
||||||
@ -1146,7 +1191,8 @@ fn main(x: int) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let mut parser = Parser::new(source, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(source, 0, &mut interner);
|
||||||
let result = parser.parse_file().unwrap();
|
let result = parser.parse_file().unwrap();
|
||||||
assert_eq!(result.decls.len(), 1);
|
assert_eq!(result.decls.len(), 1);
|
||||||
}
|
}
|
||||||
@ -1161,7 +1207,8 @@ fn bad() {
|
|||||||
|
|
||||||
fn good() {}
|
fn good() {}
|
||||||
"#;
|
"#;
|
||||||
let mut parser = Parser::new(source, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(source, 0, &mut interner);
|
||||||
let result = parser.parse_file();
|
let result = parser.parse_file();
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
}
|
}
|
||||||
@ -1169,7 +1216,8 @@ fn good() {}
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_parse_mod_fn() {
|
fn test_parse_mod_fn() {
|
||||||
let source = "mod fn test() {}";
|
let source = "mod fn test() {}";
|
||||||
let mut parser = Parser::new(source, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(source, 0, &mut interner);
|
||||||
let result = parser.parse_file().expect("mod fn should be allowed");
|
let result = parser.parse_file().expect("mod fn should be allowed");
|
||||||
if let Node::FnDecl(fn_decl) = &result.decls[0] {
|
if let Node::FnDecl(fn_decl) = &result.decls[0] {
|
||||||
assert_eq!(fn_decl.vis, Some("mod".to_string()));
|
assert_eq!(fn_decl.vis, Some("mod".to_string()));
|
||||||
@ -1181,7 +1229,8 @@ fn good() {}
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_parse_pub_fn() {
|
fn test_parse_pub_fn() {
|
||||||
let source = "pub fn test() {}";
|
let source = "pub fn test() {}";
|
||||||
let mut parser = Parser::new(source, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(source, 0, &mut interner);
|
||||||
let result = parser.parse_file().expect("pub fn should be allowed in parser");
|
let result = parser.parse_file().expect("pub fn should be allowed in parser");
|
||||||
if let Node::FnDecl(fn_decl) = &result.decls[0] {
|
if let Node::FnDecl(fn_decl) = &result.decls[0] {
|
||||||
assert_eq!(fn_decl.vis, Some("pub".to_string()));
|
assert_eq!(fn_decl.vis, Some("pub".to_string()));
|
||||||
@ -1197,12 +1246,17 @@ fn main() {
|
|||||||
return 42;
|
return 42;
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let mut parser = Parser::new(source, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(source, 0, &mut interner);
|
||||||
let result = parser.parse_file().unwrap();
|
let result = parser.parse_file().unwrap();
|
||||||
let json = serde_json::to_string_pretty(&Node::File(result)).unwrap();
|
let json = serde_json::to_string_pretty(&Node::File(result.clone())).unwrap();
|
||||||
|
|
||||||
assert!(json.contains("\"kind\": \"File\""));
|
assert!(json.contains("\"kind\": \"File\""));
|
||||||
assert!(json.contains("\"kind\": \"FnDecl\""));
|
assert!(json.contains("\"kind\": \"FnDecl\""));
|
||||||
assert!(json.contains("\"name\": \"main\""));
|
if let Node::FnDecl(fn_decl) = &result.decls[0] {
|
||||||
|
assert_eq!(interner.resolve(fn_decl.name), "main");
|
||||||
|
} else {
|
||||||
|
panic!("Expected FnDecl");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ use crate::common::diagnostics::{Diagnostic, DiagnosticBundle, DiagnosticLevel};
|
|||||||
use crate::common::spans::Span;
|
use crate::common::spans::Span;
|
||||||
use crate::frontends::pbs::ast::*;
|
use crate::frontends::pbs::ast::*;
|
||||||
use crate::frontends::pbs::symbols::*;
|
use crate::frontends::pbs::symbols::*;
|
||||||
|
use prometeu_analysis::{NameId, NameInterner};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub trait ModuleProvider {
|
pub trait ModuleProvider {
|
||||||
@ -9,9 +10,10 @@ pub trait ModuleProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Resolver<'a> {
|
pub struct Resolver<'a> {
|
||||||
|
interner: &'a NameInterner,
|
||||||
module_provider: &'a dyn ModuleProvider,
|
module_provider: &'a dyn ModuleProvider,
|
||||||
current_module: &'a ModuleSymbols,
|
current_module: &'a ModuleSymbols,
|
||||||
scopes: Vec<HashMap<String, Symbol>>,
|
scopes: Vec<HashMap<NameId, Symbol>>,
|
||||||
pub imported_symbols: ModuleSymbols,
|
pub imported_symbols: ModuleSymbols,
|
||||||
diagnostics: Vec<Diagnostic>,
|
diagnostics: Vec<Diagnostic>,
|
||||||
}
|
}
|
||||||
@ -20,8 +22,10 @@ impl<'a> Resolver<'a> {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
current_module: &'a ModuleSymbols,
|
current_module: &'a ModuleSymbols,
|
||||||
module_provider: &'a dyn ModuleProvider,
|
module_provider: &'a dyn ModuleProvider,
|
||||||
|
interner: &'a NameInterner,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
interner,
|
||||||
module_provider,
|
module_provider,
|
||||||
current_module,
|
current_module,
|
||||||
scopes: Vec::new(),
|
scopes: Vec::new(),
|
||||||
@ -58,30 +62,30 @@ impl<'a> Resolver<'a> {
|
|||||||
if let Node::ImportSpec(spec) = &*imp.spec {
|
if let Node::ImportSpec(spec) = &*imp.spec {
|
||||||
for name in &spec.path {
|
for name in &spec.path {
|
||||||
// Try to find in Type namespace
|
// Try to find in Type namespace
|
||||||
if let Some(sym) = target_symbols.type_symbols.get(name) {
|
if let Some(sym) = target_symbols.type_symbols.get(*name) {
|
||||||
if sym.visibility == Visibility::Pub {
|
if sym.visibility == Visibility::Pub {
|
||||||
let mut sym = sym.clone();
|
let mut sym = sym.clone();
|
||||||
sym.origin = Some(imp.from.clone());
|
sym.origin = Some(imp.from.clone());
|
||||||
if let Err(_) = self.imported_symbols.type_symbols.insert(sym) {
|
if let Err(_) = self.imported_symbols.type_symbols.insert(sym) {
|
||||||
self.error_duplicate_import(name, imp.span);
|
self.error_duplicate_import(*name, imp.span);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.error_visibility(sym, imp.span);
|
self.error_visibility(sym, imp.span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Try to find in Value namespace
|
// Try to find in Value namespace
|
||||||
else if let Some(sym) = target_symbols.value_symbols.get(name) {
|
else if let Some(sym) = target_symbols.value_symbols.get(*name) {
|
||||||
if sym.visibility == Visibility::Pub {
|
if sym.visibility == Visibility::Pub {
|
||||||
let mut sym = sym.clone();
|
let mut sym = sym.clone();
|
||||||
sym.origin = Some(imp.from.clone());
|
sym.origin = Some(imp.from.clone());
|
||||||
if let Err(_) = self.imported_symbols.value_symbols.insert(sym) {
|
if let Err(_) = self.imported_symbols.value_symbols.insert(sym) {
|
||||||
self.error_duplicate_import(name, imp.span);
|
self.error_duplicate_import(*name, imp.span);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.error_visibility(sym, imp.span);
|
self.error_visibility(sym, imp.span);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.error_undefined(name, imp.span);
|
self.error_undefined(*name, imp.span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,13 +143,13 @@ impl<'a> Resolver<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Node::Ident(n) => {
|
Node::Ident(n) => {
|
||||||
self.resolve_identifier(&n.name, n.span, Namespace::Value);
|
self.resolve_identifier(n.name, n.span, Namespace::Value);
|
||||||
}
|
}
|
||||||
Node::TypeName(n) => {
|
Node::TypeName(n) => {
|
||||||
self.resolve_identifier(&n.name, n.span, Namespace::Type);
|
self.resolve_identifier(n.name, n.span, Namespace::Type);
|
||||||
}
|
}
|
||||||
Node::TypeApp(n) => {
|
Node::TypeApp(n) => {
|
||||||
self.resolve_identifier(&n.base, n.span, Namespace::Type);
|
self.resolve_identifier(n.base, n.span, Namespace::Type);
|
||||||
for arg in &n.args {
|
for arg in &n.args {
|
||||||
self.resolve_type_ref(arg);
|
self.resolve_type_ref(arg);
|
||||||
}
|
}
|
||||||
@ -158,32 +162,32 @@ impl<'a> Resolver<'a> {
|
|||||||
Node::Mutate(n) => {
|
Node::Mutate(n) => {
|
||||||
self.resolve_node(&n.target);
|
self.resolve_node(&n.target);
|
||||||
self.enter_scope();
|
self.enter_scope();
|
||||||
self.define_local(&n.binding, n.span, SymbolKind::Local);
|
self.define_local(n.binding, n.span, SymbolKind::Local);
|
||||||
self.resolve_node(&n.body);
|
self.resolve_node(&n.body);
|
||||||
self.exit_scope();
|
self.exit_scope();
|
||||||
}
|
}
|
||||||
Node::Borrow(n) => {
|
Node::Borrow(n) => {
|
||||||
self.resolve_node(&n.target);
|
self.resolve_node(&n.target);
|
||||||
self.enter_scope();
|
self.enter_scope();
|
||||||
self.define_local(&n.binding, n.span, SymbolKind::Local);
|
self.define_local(n.binding, n.span, SymbolKind::Local);
|
||||||
self.resolve_node(&n.body);
|
self.resolve_node(&n.body);
|
||||||
self.exit_scope();
|
self.exit_scope();
|
||||||
}
|
}
|
||||||
Node::Peek(n) => {
|
Node::Peek(n) => {
|
||||||
self.resolve_node(&n.target);
|
self.resolve_node(&n.target);
|
||||||
self.enter_scope();
|
self.enter_scope();
|
||||||
self.define_local(&n.binding, n.span, SymbolKind::Local);
|
self.define_local(n.binding, n.span, SymbolKind::Local);
|
||||||
self.resolve_node(&n.body);
|
self.resolve_node(&n.body);
|
||||||
self.exit_scope();
|
self.exit_scope();
|
||||||
}
|
}
|
||||||
Node::MemberAccess(n) => {
|
Node::MemberAccess(n) => {
|
||||||
if let Node::Ident(id) = &*n.object {
|
if let Node::Ident(id) = &*n.object {
|
||||||
if !self.is_builtin(&id.name, Namespace::Type) {
|
if !self.is_builtin(id.name, Namespace::Type) {
|
||||||
if self.lookup_identifier(&id.name, Namespace::Value).is_none() {
|
if self.lookup_identifier(id.name, Namespace::Value).is_none() {
|
||||||
// If not found in Value namespace, try Type namespace (for Contracts/Services)
|
// If not found in Value namespace, try Type namespace (for Contracts/Services)
|
||||||
if self.lookup_identifier(&id.name, Namespace::Type).is_none() {
|
if self.lookup_identifier(id.name, Namespace::Type).is_none() {
|
||||||
// Still not found, use resolve_identifier to report error in Value namespace
|
// Still not found, use resolve_identifier to report error in Value namespace
|
||||||
self.resolve_identifier(&id.name, id.span, Namespace::Value);
|
self.resolve_identifier(id.name, id.span, Namespace::Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -199,7 +203,7 @@ impl<'a> Resolver<'a> {
|
|||||||
self.enter_scope();
|
self.enter_scope();
|
||||||
for param in &n.params {
|
for param in &n.params {
|
||||||
self.resolve_type_ref(¶m.ty);
|
self.resolve_type_ref(¶m.ty);
|
||||||
self.define_local(¶m.name, param.span, SymbolKind::Local);
|
self.define_local(param.name, param.span, SymbolKind::Local);
|
||||||
}
|
}
|
||||||
if let Some(ret) = &n.ret {
|
if let Some(ret) = &n.ret {
|
||||||
self.resolve_type_ref(ret);
|
self.resolve_type_ref(ret);
|
||||||
@ -210,7 +214,7 @@ impl<'a> Resolver<'a> {
|
|||||||
|
|
||||||
fn resolve_service_decl(&mut self, n: &ServiceDeclNode) {
|
fn resolve_service_decl(&mut self, n: &ServiceDeclNode) {
|
||||||
if let Some(ext) = &n.extends {
|
if let Some(ext) = &n.extends {
|
||||||
self.resolve_identifier(ext, n.span, Namespace::Type);
|
self.resolve_identifier(*ext, n.span, Namespace::Type);
|
||||||
}
|
}
|
||||||
for member in &n.members {
|
for member in &n.members {
|
||||||
if let Node::ServiceFnSig(sig) = member {
|
if let Node::ServiceFnSig(sig) = member {
|
||||||
@ -231,7 +235,7 @@ impl<'a> Resolver<'a> {
|
|||||||
}
|
}
|
||||||
self.enter_scope();
|
self.enter_scope();
|
||||||
for ctor in &n.constructors {
|
for ctor in &n.constructors {
|
||||||
self.define_local(&ctor.name, ctor.span, SymbolKind::Local);
|
self.define_local(ctor.name, ctor.span, SymbolKind::Local);
|
||||||
}
|
}
|
||||||
for constant in &n.constants {
|
for constant in &n.constants {
|
||||||
self.resolve_node(&constant.value);
|
self.resolve_node(&constant.value);
|
||||||
@ -256,7 +260,7 @@ impl<'a> Resolver<'a> {
|
|||||||
self.enter_scope();
|
self.enter_scope();
|
||||||
for param in &n.params {
|
for param in &n.params {
|
||||||
self.resolve_type_ref(¶m.ty);
|
self.resolve_type_ref(¶m.ty);
|
||||||
self.define_local(¶m.name, param.span, SymbolKind::Local);
|
self.define_local(param.name, param.span, SymbolKind::Local);
|
||||||
}
|
}
|
||||||
for init in &n.initializers {
|
for init in &n.initializers {
|
||||||
self.resolve_node(init);
|
self.resolve_node(init);
|
||||||
@ -278,14 +282,14 @@ impl<'a> Resolver<'a> {
|
|||||||
self.resolve_type_ref(ty);
|
self.resolve_type_ref(ty);
|
||||||
}
|
}
|
||||||
self.resolve_node(&n.init);
|
self.resolve_node(&n.init);
|
||||||
self.define_local(&n.name, n.span, SymbolKind::Local);
|
self.define_local(n.name, n.span, SymbolKind::Local);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_type_ref(&mut self, node: &Node) {
|
fn resolve_type_ref(&mut self, node: &Node) {
|
||||||
self.resolve_node(node);
|
self.resolve_node(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_identifier(&mut self, name: &str, span: Span, namespace: Namespace) -> Option<Symbol> {
|
fn resolve_identifier(&mut self, name: NameId, span: Span, namespace: Namespace) -> Option<Symbol> {
|
||||||
if self.is_builtin(name, namespace) {
|
if self.is_builtin(name, namespace) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -297,7 +301,7 @@ impl<'a> Resolver<'a> {
|
|||||||
self.diagnostics.push(Diagnostic {
|
self.diagnostics.push(Diagnostic {
|
||||||
level: DiagnosticLevel::Error,
|
level: DiagnosticLevel::Error,
|
||||||
code: Some("E_TYPE_UNKNOWN_TYPE".to_string()),
|
code: Some("E_TYPE_UNKNOWN_TYPE".to_string()),
|
||||||
message: format!("Unknown type: {}", name),
|
message: format!("Unknown type: {}", self.interner.resolve(name)),
|
||||||
span: Some(span),
|
span: Some(span),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -307,7 +311,8 @@ impl<'a> Resolver<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_builtin(&self, name: &str, namespace: Namespace) -> bool {
|
fn is_builtin(&self, name: NameId, namespace: Namespace) -> bool {
|
||||||
|
let name = self.interner.resolve(name);
|
||||||
match namespace {
|
match namespace {
|
||||||
Namespace::Type => match name {
|
Namespace::Type => match name {
|
||||||
"int" | "float" | "string" | "bool" | "void" | "optional" | "result" | "bounded" |
|
"int" | "float" | "string" | "bool" | "void" | "optional" | "result" | "bounded" |
|
||||||
@ -321,11 +326,11 @@ impl<'a> Resolver<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup_identifier(&self, name: &str, namespace: Namespace) -> Option<Symbol> {
|
fn lookup_identifier(&self, name: NameId, namespace: Namespace) -> Option<Symbol> {
|
||||||
// 1. local bindings
|
// 1. local bindings
|
||||||
if namespace == Namespace::Value {
|
if namespace == Namespace::Value {
|
||||||
for scope in self.scopes.iter().rev() {
|
for scope in self.scopes.iter().rev() {
|
||||||
if let Some(sym) = scope.get(name) {
|
if let Some(sym) = scope.get(&name) {
|
||||||
return Some(sym.clone());
|
return Some(sym.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -369,7 +374,7 @@ impl<'a> Resolver<'a> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn define_local(&mut self, name: &str, span: Span, kind: SymbolKind) {
|
fn define_local(&mut self, name: NameId, span: Span, kind: SymbolKind) {
|
||||||
let scope = self.scopes.last_mut().expect("No scope to define local");
|
let scope = self.scopes.last_mut().expect("No scope to define local");
|
||||||
|
|
||||||
// Check for collision in Type namespace at top-level?
|
// Check for collision in Type namespace at top-level?
|
||||||
@ -379,22 +384,25 @@ impl<'a> Resolver<'a> {
|
|||||||
self.diagnostics.push(Diagnostic {
|
self.diagnostics.push(Diagnostic {
|
||||||
level: DiagnosticLevel::Error,
|
level: DiagnosticLevel::Error,
|
||||||
code: Some("E_RESOLVE_NAMESPACE_COLLISION".to_string()),
|
code: Some("E_RESOLVE_NAMESPACE_COLLISION".to_string()),
|
||||||
message: format!("Local variable '{}' collides with a type name", name),
|
message: format!(
|
||||||
|
"Local variable '{}' collides with a type name",
|
||||||
|
self.interner.resolve(name)
|
||||||
|
),
|
||||||
span: Some(span),
|
span: Some(span),
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if scope.contains_key(name) {
|
if scope.contains_key(&name) {
|
||||||
self.diagnostics.push(Diagnostic {
|
self.diagnostics.push(Diagnostic {
|
||||||
level: DiagnosticLevel::Error,
|
level: DiagnosticLevel::Error,
|
||||||
code: Some("E_RESOLVE_DUPLICATE_SYMBOL".to_string()),
|
code: Some("E_RESOLVE_DUPLICATE_SYMBOL".to_string()),
|
||||||
message: format!("Duplicate local variable '{}'", name),
|
message: format!("Duplicate local variable '{}'", self.interner.resolve(name)),
|
||||||
span: Some(span),
|
span: Some(span),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
scope.insert(name.to_string(), Symbol {
|
scope.insert(name, Symbol {
|
||||||
name: name.to_string(),
|
name,
|
||||||
kind,
|
kind,
|
||||||
namespace: Namespace::Value,
|
namespace: Namespace::Value,
|
||||||
visibility: Visibility::FilePrivate,
|
visibility: Visibility::FilePrivate,
|
||||||
@ -414,20 +422,20 @@ impl<'a> Resolver<'a> {
|
|||||||
self.scopes.pop();
|
self.scopes.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error_undefined(&mut self, name: &str, span: Span) {
|
fn error_undefined(&mut self, name: NameId, span: Span) {
|
||||||
self.diagnostics.push(Diagnostic {
|
self.diagnostics.push(Diagnostic {
|
||||||
level: DiagnosticLevel::Error,
|
level: DiagnosticLevel::Error,
|
||||||
code: Some("E_RESOLVE_UNDEFINED".to_string()),
|
code: Some("E_RESOLVE_UNDEFINED".to_string()),
|
||||||
message: format!("Undefined identifier: {}", name),
|
message: format!("Undefined identifier: {}", self.interner.resolve(name)),
|
||||||
span: Some(span),
|
span: Some(span),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error_duplicate_import(&mut self, name: &str, span: Span) {
|
fn error_duplicate_import(&mut self, name: NameId, span: Span) {
|
||||||
self.diagnostics.push(Diagnostic {
|
self.diagnostics.push(Diagnostic {
|
||||||
level: DiagnosticLevel::Error,
|
level: DiagnosticLevel::Error,
|
||||||
code: Some("E_RESOLVE_DUPLICATE_SYMBOL".to_string()),
|
code: Some("E_RESOLVE_DUPLICATE_SYMBOL".to_string()),
|
||||||
message: format!("Duplicate import: {}", name),
|
message: format!("Duplicate import: {}", self.interner.resolve(name)),
|
||||||
span: Some(span),
|
span: Some(span),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -436,7 +444,10 @@ impl<'a> Resolver<'a> {
|
|||||||
self.diagnostics.push(Diagnostic {
|
self.diagnostics.push(Diagnostic {
|
||||||
level: DiagnosticLevel::Error,
|
level: DiagnosticLevel::Error,
|
||||||
code: Some("E_RESOLVE_VISIBILITY".to_string()),
|
code: Some("E_RESOLVE_VISIBILITY".to_string()),
|
||||||
message: format!("DebugSymbol '{}' is not visible here", sym.name),
|
message: format!(
|
||||||
|
"DebugSymbol '{}' is not visible here",
|
||||||
|
self.interner.resolve(sym.name)
|
||||||
|
),
|
||||||
span: Some(span),
|
span: Some(span),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -450,11 +461,13 @@ mod tests {
|
|||||||
use crate::frontends::pbs::*;
|
use crate::frontends::pbs::*;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn setup_test(source: &str) -> (ast::FileNode, usize) {
|
fn setup_test(source: &str) -> (ast::FileNode, usize, NameInterner) {
|
||||||
let mut fm = FileManager::new();
|
let mut fm = FileManager::new();
|
||||||
let file_id = fm.add(PathBuf::from("test.pbs"), source.to_string());
|
let file_id = fm.add(PathBuf::from("test.pbs"), source.to_string());
|
||||||
let mut parser = parser::Parser::new(source, file_id);
|
let mut interner = NameInterner::new();
|
||||||
(parser.parse_file().expect("Parsing failed"), file_id)
|
let mut parser = parser::Parser::new(source, file_id, &mut interner);
|
||||||
|
let ast = parser.parse_file().expect("Parsing failed");
|
||||||
|
(ast, file_id, interner)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -463,8 +476,8 @@ mod tests {
|
|||||||
declare struct Foo {}
|
declare struct Foo {}
|
||||||
declare struct Foo {}
|
declare struct Foo {}
|
||||||
";
|
";
|
||||||
let (ast, _) = setup_test(source);
|
let (ast, _, mut interner) = setup_test(source);
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let result = collector.collect(&ast);
|
let result = collector.collect(&ast);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
@ -478,8 +491,8 @@ mod tests {
|
|||||||
declare struct Foo {}
|
declare struct Foo {}
|
||||||
fn Foo() {}
|
fn Foo() {}
|
||||||
";
|
";
|
||||||
let (ast, _) = setup_test(source);
|
let (ast, _, mut interner) = setup_test(source);
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let result = collector.collect(&ast);
|
let result = collector.collect(&ast);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
@ -494,8 +507,8 @@ mod tests {
|
|||||||
let x = y;
|
let x = y;
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
let (ast, _) = setup_test(source);
|
let (ast, _, mut interner) = setup_test(source);
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let (ts, vs) = collector.collect(&ast).expect("Collection failed");
|
let (ts, vs) = collector.collect(&ast).expect("Collection failed");
|
||||||
let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs };
|
let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs };
|
||||||
|
|
||||||
@ -504,7 +517,7 @@ mod tests {
|
|||||||
fn get_module_symbols(&self, _path: &str) -> Option<&ModuleSymbols> { None }
|
fn get_module_symbols(&self, _path: &str) -> Option<&ModuleSymbols> { None }
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut resolver = Resolver::new(&ms, &EmptyProvider);
|
let mut resolver = Resolver::new(&ms, &EmptyProvider, &interner);
|
||||||
let result = resolver.resolve(&ast);
|
let result = resolver.resolve(&ast);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
@ -520,8 +533,8 @@ mod tests {
|
|||||||
let y = x;
|
let y = x;
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
let (ast, _) = setup_test(source);
|
let (ast, _, mut interner) = setup_test(source);
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let (ts, vs) = collector.collect(&ast).expect("Collection failed");
|
let (ts, vs) = collector.collect(&ast).expect("Collection failed");
|
||||||
let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs };
|
let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs };
|
||||||
|
|
||||||
@ -530,7 +543,7 @@ mod tests {
|
|||||||
fn get_module_symbols(&self, _path: &str) -> Option<&ModuleSymbols> { None }
|
fn get_module_symbols(&self, _path: &str) -> Option<&ModuleSymbols> { None }
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut resolver = Resolver::new(&ms, &EmptyProvider);
|
let mut resolver = Resolver::new(&ms, &EmptyProvider, &interner);
|
||||||
let result = resolver.resolve(&ast);
|
let result = resolver.resolve(&ast);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
@ -542,8 +555,8 @@ mod tests {
|
|||||||
import PrivateType from \"./other.pbs\"
|
import PrivateType from \"./other.pbs\"
|
||||||
fn main() {}
|
fn main() {}
|
||||||
";
|
";
|
||||||
let (ast, _) = setup_test(source);
|
let (ast, _, mut interner) = setup_test(source);
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let (ts, vs) = collector.collect(&ast).expect("Collection failed");
|
let (ts, vs) = collector.collect(&ast).expect("Collection failed");
|
||||||
let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs };
|
let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs };
|
||||||
|
|
||||||
@ -558,7 +571,7 @@ mod tests {
|
|||||||
|
|
||||||
let mut other_ts = SymbolTable::new();
|
let mut other_ts = SymbolTable::new();
|
||||||
other_ts.insert(Symbol {
|
other_ts.insert(Symbol {
|
||||||
name: "PrivateType".to_string(),
|
name: interner.intern("PrivateType"),
|
||||||
kind: SymbolKind::Struct,
|
kind: SymbolKind::Struct,
|
||||||
namespace: Namespace::Type,
|
namespace: Namespace::Type,
|
||||||
visibility: Visibility::FilePrivate,
|
visibility: Visibility::FilePrivate,
|
||||||
@ -572,7 +585,7 @@ mod tests {
|
|||||||
other: ModuleSymbols { type_symbols: other_ts, value_symbols: SymbolTable::new() },
|
other: ModuleSymbols { type_symbols: other_ts, value_symbols: SymbolTable::new() },
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut resolver = Resolver::new(&ms, &mock_provider);
|
let mut resolver = Resolver::new(&ms, &mock_provider, &interner);
|
||||||
let result = resolver.resolve(&ast);
|
let result = resolver.resolve(&ast);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
@ -588,8 +601,8 @@ mod tests {
|
|||||||
let x: PubType = 10;
|
let x: PubType = 10;
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
let (ast, _) = setup_test(source);
|
let (ast, _, mut interner) = setup_test(source);
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let (ts, vs) = collector.collect(&ast).expect("Collection failed");
|
let (ts, vs) = collector.collect(&ast).expect("Collection failed");
|
||||||
let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs };
|
let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs };
|
||||||
|
|
||||||
@ -604,7 +617,7 @@ mod tests {
|
|||||||
|
|
||||||
let mut other_ts = SymbolTable::new();
|
let mut other_ts = SymbolTable::new();
|
||||||
other_ts.insert(Symbol {
|
other_ts.insert(Symbol {
|
||||||
name: "PubType".to_string(),
|
name: interner.intern("PubType"),
|
||||||
kind: SymbolKind::Struct,
|
kind: SymbolKind::Struct,
|
||||||
namespace: Namespace::Type,
|
namespace: Namespace::Type,
|
||||||
visibility: Visibility::Pub,
|
visibility: Visibility::Pub,
|
||||||
@ -618,7 +631,7 @@ mod tests {
|
|||||||
other: ModuleSymbols { type_symbols: other_ts, value_symbols: SymbolTable::new() },
|
other: ModuleSymbols { type_symbols: other_ts, value_symbols: SymbolTable::new() },
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut resolver = Resolver::new(&ms, &mock_provider);
|
let mut resolver = Resolver::new(&ms, &mock_provider, &interner);
|
||||||
let result = resolver.resolve(&ast);
|
let result = resolver.resolve(&ast);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
@ -630,8 +643,8 @@ mod tests {
|
|||||||
import NonExistent from \"./missing.pbs\"
|
import NonExistent from \"./missing.pbs\"
|
||||||
fn main() {}
|
fn main() {}
|
||||||
";
|
";
|
||||||
let (ast, _) = setup_test(source);
|
let (ast, _, interner) = setup_test(source);
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let (ts, vs) = collector.collect(&ast).expect("Collection failed");
|
let (ts, vs) = collector.collect(&ast).expect("Collection failed");
|
||||||
let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs };
|
let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs };
|
||||||
|
|
||||||
@ -640,7 +653,7 @@ mod tests {
|
|||||||
fn get_module_symbols(&self, _path: &str) -> Option<&ModuleSymbols> { None }
|
fn get_module_symbols(&self, _path: &str) -> Option<&ModuleSymbols> { None }
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut resolver = Resolver::new(&ms, &EmptyProvider);
|
let mut resolver = Resolver::new(&ms, &EmptyProvider, &interner);
|
||||||
let result = resolver.resolve(&ast);
|
let result = resolver.resolve(&ast);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use crate::common::spans::Span;
|
use crate::common::spans::Span;
|
||||||
use crate::frontends::pbs::types::PbsType;
|
use crate::frontends::pbs::types::PbsType;
|
||||||
|
use prometeu_analysis::NameId;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
@ -28,7 +29,7 @@ pub enum Namespace {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Symbol {
|
pub struct Symbol {
|
||||||
pub name: String,
|
pub name: NameId,
|
||||||
pub kind: SymbolKind,
|
pub kind: SymbolKind,
|
||||||
pub namespace: Namespace,
|
pub namespace: Namespace,
|
||||||
pub visibility: Visibility,
|
pub visibility: Visibility,
|
||||||
@ -40,7 +41,7 @@ pub struct Symbol {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SymbolTable {
|
pub struct SymbolTable {
|
||||||
pub symbols: HashMap<String, Symbol>,
|
pub symbols: HashMap<NameId, Symbol>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -65,15 +66,15 @@ impl SymbolTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, symbol: Symbol) -> Result<(), Symbol> {
|
pub fn insert(&mut self, symbol: Symbol) -> Result<(), ()> {
|
||||||
if let Some(existing) = self.symbols.get(&symbol.name) {
|
if self.symbols.contains_key(&symbol.name) {
|
||||||
return Err(existing.clone());
|
return Err(());
|
||||||
}
|
}
|
||||||
self.symbols.insert(symbol.name.clone(), symbol);
|
self.symbols.insert(symbol.name, symbol);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, name: &str) -> Option<&Symbol> {
|
pub fn get(&self, name: NameId) -> Option<&Symbol> {
|
||||||
self.symbols.get(name)
|
self.symbols.get(&name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,12 +5,14 @@ use crate::frontends::pbs::contracts::ContractRegistry;
|
|||||||
use crate::frontends::pbs::resolver::ModuleProvider;
|
use crate::frontends::pbs::resolver::ModuleProvider;
|
||||||
use crate::frontends::pbs::symbols::*;
|
use crate::frontends::pbs::symbols::*;
|
||||||
use crate::frontends::pbs::types::PbsType;
|
use crate::frontends::pbs::types::PbsType;
|
||||||
|
use prometeu_analysis::{NameId, NameInterner};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub struct TypeChecker<'a> {
|
pub struct TypeChecker<'a> {
|
||||||
module_symbols: &'a mut ModuleSymbols,
|
module_symbols: &'a mut ModuleSymbols,
|
||||||
imported_symbols: &'a ModuleSymbols,
|
imported_symbols: &'a ModuleSymbols,
|
||||||
_module_provider: &'a dyn ModuleProvider,
|
_module_provider: &'a dyn ModuleProvider,
|
||||||
|
interner: &'a NameInterner,
|
||||||
scopes: Vec<HashMap<String, PbsType>>,
|
scopes: Vec<HashMap<String, PbsType>>,
|
||||||
mut_bindings: Vec<HashMap<String, bool>>,
|
mut_bindings: Vec<HashMap<String, bool>>,
|
||||||
current_return_type: Option<PbsType>,
|
current_return_type: Option<PbsType>,
|
||||||
@ -26,11 +28,13 @@ impl<'a> TypeChecker<'a> {
|
|||||||
module_symbols: &'a mut ModuleSymbols,
|
module_symbols: &'a mut ModuleSymbols,
|
||||||
imported_symbols: &'a ModuleSymbols,
|
imported_symbols: &'a ModuleSymbols,
|
||||||
module_provider: &'a dyn ModuleProvider,
|
module_provider: &'a dyn ModuleProvider,
|
||||||
|
interner: &'a NameInterner,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
module_symbols,
|
module_symbols,
|
||||||
imported_symbols,
|
imported_symbols,
|
||||||
_module_provider: module_provider,
|
_module_provider: module_provider,
|
||||||
|
interner,
|
||||||
scopes: Vec::new(),
|
scopes: Vec::new(),
|
||||||
mut_bindings: Vec::new(),
|
mut_bindings: Vec::new(),
|
||||||
current_return_type: None,
|
current_return_type: None,
|
||||||
@ -84,14 +88,15 @@ impl<'a> TypeChecker<'a> {
|
|||||||
Node::ServiceDecl(n) => {
|
Node::ServiceDecl(n) => {
|
||||||
// For service, the symbol's type is just Service(name)
|
// For service, the symbol's type is just Service(name)
|
||||||
if let Some(sym) = self.module_symbols.type_symbols.symbols.get_mut(&n.name) {
|
if let Some(sym) = self.module_symbols.type_symbols.symbols.get_mut(&n.name) {
|
||||||
sym.ty = Some(PbsType::Service(n.name.clone()));
|
sym.ty = Some(PbsType::Service(self.interner.resolve(n.name).to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Node::TypeDecl(n) => {
|
Node::TypeDecl(n) => {
|
||||||
|
let type_name = self.interner.resolve(n.name).to_string();
|
||||||
let ty = match n.type_kind.as_str() {
|
let ty = match n.type_kind.as_str() {
|
||||||
"struct" => PbsType::Struct(n.name.clone()),
|
"struct" => PbsType::Struct(type_name.clone()),
|
||||||
"contract" => PbsType::Contract(n.name.clone()),
|
"contract" => PbsType::Contract(type_name.clone()),
|
||||||
"error" => PbsType::ErrorType(n.name.clone()),
|
"error" => PbsType::ErrorType(type_name.clone()),
|
||||||
_ => PbsType::Void,
|
_ => PbsType::Void,
|
||||||
};
|
};
|
||||||
if let Some(sym) = self.module_symbols.type_symbols.symbols.get_mut(&n.name) {
|
if let Some(sym) = self.module_symbols.type_symbols.symbols.get_mut(&n.name) {
|
||||||
@ -117,7 +122,7 @@ impl<'a> TypeChecker<'a> {
|
|||||||
params: params.clone(),
|
params: params.clone(),
|
||||||
return_type: Box::new(ty.clone()),
|
return_type: Box::new(ty.clone()),
|
||||||
};
|
};
|
||||||
ctors.insert(n.name.clone(), default_ctor_ty);
|
ctors.insert(type_name.clone(), default_ctor_ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
for ctor in &n.constructors {
|
for ctor in &n.constructors {
|
||||||
@ -129,9 +134,9 @@ impl<'a> TypeChecker<'a> {
|
|||||||
params,
|
params,
|
||||||
return_type: Box::new(ty.clone()),
|
return_type: Box::new(ty.clone()),
|
||||||
};
|
};
|
||||||
ctors.insert(ctor.name.clone(), ctor_ty);
|
ctors.insert(self.interner.resolve(ctor.name).to_string(), ctor_ty);
|
||||||
}
|
}
|
||||||
self.struct_constructors.insert(n.name.clone(), ctors);
|
self.struct_constructors.insert(type_name.clone(), ctors);
|
||||||
|
|
||||||
// Resolve methods
|
// Resolve methods
|
||||||
let mut methods = HashMap::new();
|
let mut methods = HashMap::new();
|
||||||
@ -146,11 +151,11 @@ impl<'a> TypeChecker<'a> {
|
|||||||
params,
|
params,
|
||||||
return_type: Box::new(self.resolve_type_node(&m.ret)),
|
return_type: Box::new(self.resolve_type_node(&m.ret)),
|
||||||
};
|
};
|
||||||
methods.insert(m.name.clone(), m_ty);
|
methods.insert(self.interner.resolve(m.name).to_string(), m_ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.struct_methods.insert(n.name.clone(), methods);
|
self.struct_methods.insert(type_name, methods);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -206,28 +211,30 @@ impl<'a> TypeChecker<'a> {
|
|||||||
Node::IfExpr(n) => self.check_if_expr(n),
|
Node::IfExpr(n) => self.check_if_expr(n),
|
||||||
Node::WhenExpr(n) => self.check_when_expr(n),
|
Node::WhenExpr(n) => self.check_when_expr(n),
|
||||||
Node::Alloc(n) => self.check_alloc(n),
|
Node::Alloc(n) => self.check_alloc(n),
|
||||||
Node::Mutate(n) => self.check_hip(n.span, &n.target, &n.binding, &n.body, true),
|
Node::Mutate(n) => self.check_hip(n.span, &n.target, n.binding, &n.body, true),
|
||||||
Node::Borrow(n) => self.check_hip(n.span, &n.target, &n.binding, &n.body, false),
|
Node::Borrow(n) => self.check_hip(n.span, &n.target, n.binding, &n.body, false),
|
||||||
Node::Peek(n) => self.check_hip(n.span, &n.target, &n.binding, &n.body, false),
|
Node::Peek(n) => self.check_hip(n.span, &n.target, n.binding, &n.body, false),
|
||||||
Node::MemberAccess(n) => self.check_member_access(n),
|
Node::MemberAccess(n) => self.check_member_access(n),
|
||||||
_ => PbsType::Void,
|
_ => PbsType::Void,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_member_access(&mut self, n: &MemberAccessNode) -> PbsType {
|
fn check_member_access(&mut self, n: &MemberAccessNode) -> PbsType {
|
||||||
|
let member_str = self.interner.resolve(n.member);
|
||||||
if let Node::Ident(id) = &*n.object {
|
if let Node::Ident(id) = &*n.object {
|
||||||
|
let name_str = self.interner.resolve(id.name);
|
||||||
// Check if it's a local first
|
// Check if it's a local first
|
||||||
let is_local = self.scopes.iter().any(|s| s.contains_key(&id.name));
|
let is_local = self.scopes.iter().any(|s| s.contains_key(name_str));
|
||||||
|
|
||||||
if !is_local {
|
if !is_local {
|
||||||
// Check if it's a known host contract
|
// Check if it's a known host contract
|
||||||
let sym_opt = self.module_symbols.type_symbols.get(&id.name)
|
let sym_opt = self.module_symbols.type_symbols.get(id.name)
|
||||||
.or_else(|| self.imported_symbols.type_symbols.get(&id.name));
|
.or_else(|| self.imported_symbols.type_symbols.get(id.name));
|
||||||
|
|
||||||
if let Some(sym) = sym_opt {
|
if let Some(sym) = sym_opt {
|
||||||
if sym.kind == SymbolKind::Contract && sym.is_host {
|
if sym.kind == SymbolKind::Contract && sym.is_host {
|
||||||
// Check if the method exists in registry
|
// Check if the method exists in registry
|
||||||
if let Some(method) = self.contract_registry.get_method(&id.name, &n.member) {
|
if let Some(method) = self.contract_registry.get_method(name_str, member_str) {
|
||||||
return PbsType::Function {
|
return PbsType::Function {
|
||||||
params: method.params.clone(),
|
params: method.params.clone(),
|
||||||
return_type: Box::new(method.return_type.clone()),
|
return_type: Box::new(method.return_type.clone()),
|
||||||
@ -236,7 +243,7 @@ impl<'a> TypeChecker<'a> {
|
|||||||
self.diagnostics.push(Diagnostic {
|
self.diagnostics.push(Diagnostic {
|
||||||
level: DiagnosticLevel::Error,
|
level: DiagnosticLevel::Error,
|
||||||
code: Some("E_RESOLVE_UNDEFINED".to_string()),
|
code: Some("E_RESOLVE_UNDEFINED".to_string()),
|
||||||
message: format!("Method '{}' not found on host contract '{}'", n.member, id.name),
|
message: format!("Method '{}' not found on host contract '{}'", member_str, name_str),
|
||||||
span: Some(n.span),
|
span: Some(n.span),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -244,8 +251,8 @@ impl<'a> TypeChecker<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// v0: Suporte explícito às constantes de Color
|
// v0: Suporte explícito às constantes de Color
|
||||||
if sym.kind == SymbolKind::Struct && id.name == "Color" {
|
if sym.kind == SymbolKind::Struct && name_str == "Color" {
|
||||||
match n.member.as_str() {
|
match member_str {
|
||||||
"BLACK" | "WHITE" | "RED" | "GREEN" | "BLUE" => {
|
"BLACK" | "WHITE" | "RED" | "GREEN" | "BLUE" => {
|
||||||
return PbsType::Struct("Color".to_string());
|
return PbsType::Struct("Color".to_string());
|
||||||
}
|
}
|
||||||
@ -255,22 +262,22 @@ impl<'a> TypeChecker<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Builtin Struct Associated Members (Static/Constants)
|
// Builtin Struct Associated Members (Static/Constants)
|
||||||
if let Some(constants) = self.struct_constants.get(&id.name) {
|
if let Some(constants) = self.struct_constants.get(name_str) {
|
||||||
if let Some(ty) = constants.get(&n.member) {
|
if let Some(ty) = constants.get(member_str) {
|
||||||
return ty.clone();
|
return ty.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback for constructors if used as Type.alias(...)
|
// Fallback for constructors if used as Type.alias(...)
|
||||||
if let Some(ctors) = self.struct_constructors.get(&id.name) {
|
if let Some(ctors) = self.struct_constructors.get(name_str) {
|
||||||
if let Some(ty) = ctors.get(&n.member) {
|
if let Some(ty) = ctors.get(member_str) {
|
||||||
return ty.clone();
|
return ty.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback for static methods if used as Type.method(...)
|
// Fallback for static methods if used as Type.method(...)
|
||||||
if let Some(methods) = self.struct_methods.get(&id.name) {
|
if let Some(methods) = self.struct_methods.get(name_str) {
|
||||||
if let Some(ty) = methods.get(&n.member) {
|
if let Some(ty) = methods.get(member_str) {
|
||||||
return ty.clone();
|
return ty.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -280,7 +287,7 @@ impl<'a> TypeChecker<'a> {
|
|||||||
let obj_ty = self.check_node(&n.object);
|
let obj_ty = self.check_node(&n.object);
|
||||||
if let PbsType::Struct(ref name) = obj_ty {
|
if let PbsType::Struct(ref name) = obj_ty {
|
||||||
if let Some(methods) = self.struct_methods.get(name) {
|
if let Some(methods) = self.struct_methods.get(name) {
|
||||||
if let Some(ty) = methods.get(&n.member) {
|
if let Some(ty) = methods.get(member_str) {
|
||||||
// If it's a method call on an instance, the first parameter (self) is implicit
|
// If it's a method call on an instance, the first parameter (self) is implicit
|
||||||
if let PbsType::Function { mut params, return_type } = ty.clone() {
|
if let PbsType::Function { mut params, return_type } = ty.clone() {
|
||||||
if !params.is_empty() {
|
if !params.is_empty() {
|
||||||
@ -299,7 +306,7 @@ impl<'a> TypeChecker<'a> {
|
|||||||
PbsType::Struct(ref name) => {
|
PbsType::Struct(ref name) => {
|
||||||
match name.as_str() {
|
match name.as_str() {
|
||||||
"Color" => {
|
"Color" => {
|
||||||
match n.member.as_str() {
|
match member_str {
|
||||||
"value" => return PbsType::Bounded,
|
"value" => return PbsType::Bounded,
|
||||||
"raw" => return PbsType::Function {
|
"raw" => return PbsType::Function {
|
||||||
params: vec![], // self is implicit
|
params: vec![], // self is implicit
|
||||||
@ -309,14 +316,14 @@ impl<'a> TypeChecker<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"ButtonState" => {
|
"ButtonState" => {
|
||||||
match n.member.as_str() {
|
match member_str {
|
||||||
"pressed" | "released" | "down" => return PbsType::Bool,
|
"pressed" | "released" | "down" => return PbsType::Bool,
|
||||||
"hold_frames" => return PbsType::Bounded,
|
"hold_frames" => return PbsType::Bounded,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"Pad" => {
|
"Pad" => {
|
||||||
match n.member.as_str() {
|
match member_str {
|
||||||
"up" | "down" | "left" | "right" | "a" | "b" | "x" | "y" | "l" | "r" | "start" | "select" => {
|
"up" | "down" | "left" | "right" | "a" | "b" | "x" | "y" | "l" | "r" | "start" | "select" => {
|
||||||
return PbsType::Struct("ButtonState".to_string());
|
return PbsType::Struct("ButtonState".to_string());
|
||||||
}
|
}
|
||||||
@ -330,7 +337,7 @@ impl<'a> TypeChecker<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"Touch" => {
|
"Touch" => {
|
||||||
match n.member.as_str() {
|
match member_str {
|
||||||
"f" => return PbsType::Struct("ButtonState".to_string()),
|
"f" => return PbsType::Struct("ButtonState".to_string()),
|
||||||
"x" | "y" => return PbsType::Int,
|
"x" | "y" => return PbsType::Int,
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -343,7 +350,7 @@ impl<'a> TypeChecker<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if obj_ty != PbsType::Void {
|
if obj_ty != PbsType::Void {
|
||||||
let msg = format!("Member '{}' not found on type {:?}", n.member, obj_ty);
|
let msg = format!("Member '{}' not found on type {:?}", member_str, obj_ty);
|
||||||
self.diagnostics.push(Diagnostic {
|
self.diagnostics.push(Diagnostic {
|
||||||
level: DiagnosticLevel::Error,
|
level: DiagnosticLevel::Error,
|
||||||
code: Some("E_RESOLVE_UNDEFINED".to_string()),
|
code: Some("E_RESOLVE_UNDEFINED".to_string()),
|
||||||
@ -361,7 +368,7 @@ impl<'a> TypeChecker<'a> {
|
|||||||
PbsType::Contract(format!("Gate<{}>", ty)) // Approximation for v0
|
PbsType::Contract(format!("Gate<{}>", ty)) // Approximation for v0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_hip(&mut self, _span: Span, target: &Node, binding: &str, body: &Node, is_mut: bool) -> PbsType {
|
fn check_hip(&mut self, _span: Span, target: &Node, binding: NameId, body: &Node, is_mut: bool) -> PbsType {
|
||||||
let target_ty = self.check_node(target);
|
let target_ty = self.check_node(target);
|
||||||
// In v0, we assume target is a gate. We bind the inner type to the binding.
|
// In v0, we assume target is a gate. We bind the inner type to the binding.
|
||||||
let inner_ty = match target_ty {
|
let inner_ty = match target_ty {
|
||||||
@ -380,20 +387,21 @@ impl<'a> TypeChecker<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.enter_scope();
|
self.enter_scope();
|
||||||
self.define_local(binding, inner_ty, is_mut);
|
let binding_str = self.interner.resolve(binding);
|
||||||
|
self.define_local(binding_str, inner_ty, is_mut);
|
||||||
let body_ty = self.check_node(body);
|
let body_ty = self.check_node(body);
|
||||||
self.exit_scope();
|
self.exit_scope();
|
||||||
body_ty
|
body_ty
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_fn_decl(&mut self, n: &FnDeclNode) {
|
fn check_fn_decl(&mut self, n: &FnDeclNode) {
|
||||||
let sig = self.module_symbols.value_symbols.get(&n.name).and_then(|s| s.ty.clone());
|
let sig = self.module_symbols.value_symbols.get(n.name).and_then(|s| s.ty.clone());
|
||||||
if let Some(PbsType::Function { params, return_type }) = sig {
|
if let Some(PbsType::Function { params, return_type }) = sig {
|
||||||
self.enter_scope();
|
self.enter_scope();
|
||||||
self.current_return_type = Some(*return_type.clone());
|
self.current_return_type = Some(*return_type.clone());
|
||||||
|
|
||||||
for (param, ty) in n.params.iter().zip(params.iter()) {
|
for (param, ty) in n.params.iter().zip(params.iter()) {
|
||||||
self.define_local(¶m.name, ty.clone(), false);
|
self.define_local(self.interner.resolve(param.name), ty.clone(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
let _body_ty = self.check_node(&n.body);
|
let _body_ty = self.check_node(&n.body);
|
||||||
@ -410,7 +418,11 @@ impl<'a> TypeChecker<'a> {
|
|||||||
self.diagnostics.push(Diagnostic {
|
self.diagnostics.push(Diagnostic {
|
||||||
level: DiagnosticLevel::Error,
|
level: DiagnosticLevel::Error,
|
||||||
code: Some("E_TYPE_RETURN_PATH".to_string()),
|
code: Some("E_TYPE_RETURN_PATH".to_string()),
|
||||||
message: format!("Function '{}' must return a value of type {}", n.name, return_type),
|
message: format!(
|
||||||
|
"Function '{}' must return a value of type {}",
|
||||||
|
self.interner.resolve(n.name),
|
||||||
|
return_type
|
||||||
|
),
|
||||||
span: Some(n.span),
|
span: Some(n.span),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -452,44 +464,45 @@ impl<'a> TypeChecker<'a> {
|
|||||||
init_ty
|
init_ty
|
||||||
};
|
};
|
||||||
|
|
||||||
self.define_local(&n.name, final_ty, n.is_mut);
|
self.define_local(self.interner.resolve(n.name), final_ty, n.is_mut);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_identifier(&mut self, n: &IdentNode) -> PbsType {
|
fn check_identifier(&mut self, n: &IdentNode) -> PbsType {
|
||||||
|
let name_str = self.interner.resolve(n.name);
|
||||||
// Check locals
|
// Check locals
|
||||||
for scope in self.scopes.iter().rev() {
|
for scope in self.scopes.iter().rev() {
|
||||||
if let Some(ty) = scope.get(&n.name) {
|
if let Some(ty) = scope.get(name_str) {
|
||||||
return ty.clone();
|
return ty.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check module symbols
|
// Check module symbols
|
||||||
if let Some(sym) = self.module_symbols.value_symbols.get(&n.name) {
|
if let Some(sym) = self.module_symbols.value_symbols.get(n.name) {
|
||||||
if let Some(ty) = &sym.ty {
|
if let Some(ty) = &sym.ty {
|
||||||
return ty.clone();
|
return ty.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check imported symbols
|
// Check imported symbols
|
||||||
if let Some(sym) = self.imported_symbols.value_symbols.get(&n.name) {
|
if let Some(sym) = self.imported_symbols.value_symbols.get(n.name) {
|
||||||
if let Some(ty) = &sym.ty {
|
if let Some(ty) = &sym.ty {
|
||||||
return ty.clone();
|
return ty.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback for default constructor: check if it's a struct name
|
// Fallback for default constructor: check if it's a struct name
|
||||||
if let Some(ctors) = self.struct_constructors.get(&n.name) {
|
if let Some(ctors) = self.struct_constructors.get(name_str) {
|
||||||
if let Some(ty) = ctors.get(&n.name) {
|
if let Some(ty) = ctors.get(name_str) {
|
||||||
return ty.clone();
|
return ty.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Built-ins (some, none, ok, err might be handled as calls or special keywords)
|
// Built-ins (some, none, ok, err might be handled as calls or special keywords)
|
||||||
// For v0, let's treat none as a special literal or identifier
|
// For v0, let's treat none as a special literal or identifier
|
||||||
if n.name == "none" {
|
if name_str == "none" {
|
||||||
return PbsType::None;
|
return PbsType::None;
|
||||||
}
|
}
|
||||||
if n.name == "true" || n.name == "false" {
|
if name_str == "true" || name_str == "false" {
|
||||||
return PbsType::Bool;
|
return PbsType::Bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -502,7 +515,7 @@ impl<'a> TypeChecker<'a> {
|
|||||||
|
|
||||||
// Handle special built-in "constructors"
|
// Handle special built-in "constructors"
|
||||||
if let Node::Ident(id) = &*n.callee {
|
if let Node::Ident(id) = &*n.callee {
|
||||||
match id.name.as_str() {
|
match self.interner.resolve(id.name) {
|
||||||
"some" => {
|
"some" => {
|
||||||
if n.args.len() == 1 {
|
if n.args.len() == 1 {
|
||||||
let inner_ty = self.check_node(&n.args[0]);
|
let inner_ty = self.check_node(&n.args[0]);
|
||||||
@ -673,9 +686,10 @@ impl<'a> TypeChecker<'a> {
|
|||||||
self.check_constructor_decl(constructor);
|
self.check_constructor_decl(constructor);
|
||||||
}
|
}
|
||||||
|
|
||||||
let struct_ty = PbsType::Struct(n.name.clone());
|
let type_name = self.interner.resolve(n.name).to_string();
|
||||||
|
let struct_ty = PbsType::Struct(type_name.clone());
|
||||||
let mut constants_scope = HashMap::new();
|
let mut constants_scope = HashMap::new();
|
||||||
if let Some(ctors) = self.struct_constructors.get(&n.name) {
|
if let Some(ctors) = self.struct_constructors.get(&type_name) {
|
||||||
for (name, ty) in ctors {
|
for (name, ty) in ctors {
|
||||||
constants_scope.insert(name.clone(), ty.clone());
|
constants_scope.insert(name.clone(), ty.clone());
|
||||||
}
|
}
|
||||||
@ -688,10 +702,10 @@ impl<'a> TypeChecker<'a> {
|
|||||||
if !self.is_assignable(&struct_ty, &val_ty) {
|
if !self.is_assignable(&struct_ty, &val_ty) {
|
||||||
self.error_type_mismatch(&struct_ty, &val_ty, constant.span);
|
self.error_type_mismatch(&struct_ty, &val_ty, constant.span);
|
||||||
}
|
}
|
||||||
constants_map.insert(constant.name.clone(), struct_ty.clone());
|
constants_map.insert(self.interner.resolve(constant.name).to_string(), struct_ty.clone());
|
||||||
}
|
}
|
||||||
self.scopes.pop();
|
self.scopes.pop();
|
||||||
self.struct_constants.insert(n.name.clone(), constants_map);
|
self.struct_constants.insert(type_name, constants_map);
|
||||||
|
|
||||||
if let Some(body) = &n.body {
|
if let Some(body) = &n.body {
|
||||||
self.check_node(body);
|
self.check_node(body);
|
||||||
@ -702,7 +716,7 @@ impl<'a> TypeChecker<'a> {
|
|||||||
self.enter_scope();
|
self.enter_scope();
|
||||||
for param in &n.params {
|
for param in &n.params {
|
||||||
let ty = self.resolve_type_node(¶m.ty);
|
let ty = self.resolve_type_node(¶m.ty);
|
||||||
self.define_local(¶m.name, ty, false);
|
self.define_local(self.interner.resolve(param.name), ty, false);
|
||||||
}
|
}
|
||||||
for init in &n.initializers {
|
for init in &n.initializers {
|
||||||
self.check_node(init);
|
self.check_node(init);
|
||||||
@ -714,29 +728,30 @@ impl<'a> TypeChecker<'a> {
|
|||||||
fn resolve_type_node(&mut self, node: &Node) -> PbsType {
|
fn resolve_type_node(&mut self, node: &Node) -> PbsType {
|
||||||
match node {
|
match node {
|
||||||
Node::TypeName(tn) => {
|
Node::TypeName(tn) => {
|
||||||
match tn.name.as_str() {
|
let name_str = self.interner.resolve(tn.name);
|
||||||
|
match name_str {
|
||||||
"int" => PbsType::Int,
|
"int" => PbsType::Int,
|
||||||
"float" => PbsType::Float,
|
"float" => PbsType::Float,
|
||||||
"bool" => PbsType::Bool,
|
"bool" => PbsType::Bool,
|
||||||
"string" => PbsType::String,
|
"string" => PbsType::String,
|
||||||
"void" => PbsType::Void,
|
"void" => PbsType::Void,
|
||||||
"bounded" => PbsType::Bounded,
|
"bounded" => PbsType::Bounded,
|
||||||
"Color" | "ButtonState" | "Pad" | "Touch" => PbsType::Struct(tn.name.clone()),
|
"Color" | "ButtonState" | "Pad" | "Touch" => PbsType::Struct(name_str.to_string()),
|
||||||
_ => {
|
_ => {
|
||||||
// Look up in symbol table
|
// Look up in symbol table
|
||||||
if let Some(sym) = self.lookup_type(&tn.name) {
|
if let Some(sym) = self.lookup_type(tn.name) {
|
||||||
match sym.kind {
|
match sym.kind {
|
||||||
SymbolKind::Struct => PbsType::Struct(tn.name.clone()),
|
SymbolKind::Struct => PbsType::Struct(name_str.to_string()),
|
||||||
SymbolKind::Service => PbsType::Service(tn.name.clone()),
|
SymbolKind::Service => PbsType::Service(name_str.to_string()),
|
||||||
SymbolKind::Contract => PbsType::Contract(tn.name.clone()),
|
SymbolKind::Contract => PbsType::Contract(name_str.to_string()),
|
||||||
SymbolKind::ErrorType => PbsType::ErrorType(tn.name.clone()),
|
SymbolKind::ErrorType => PbsType::ErrorType(name_str.to_string()),
|
||||||
_ => PbsType::Void,
|
_ => PbsType::Void,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.diagnostics.push(Diagnostic {
|
self.diagnostics.push(Diagnostic {
|
||||||
level: DiagnosticLevel::Error,
|
level: DiagnosticLevel::Error,
|
||||||
code: Some("E_TYPE_UNKNOWN_TYPE".to_string()),
|
code: Some("E_TYPE_UNKNOWN_TYPE".to_string()),
|
||||||
message: format!("Unknown type: {}", tn.name),
|
message: format!("Unknown type: {}", name_str),
|
||||||
span: Some(tn.span),
|
span: Some(tn.span),
|
||||||
});
|
});
|
||||||
PbsType::Void
|
PbsType::Void
|
||||||
@ -745,7 +760,7 @@ impl<'a> TypeChecker<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Node::TypeApp(ta) => {
|
Node::TypeApp(ta) => {
|
||||||
match ta.base.as_str() {
|
match self.interner.resolve(ta.base) {
|
||||||
"optional" => {
|
"optional" => {
|
||||||
if ta.args.len() == 1 {
|
if ta.args.len() == 1 {
|
||||||
PbsType::Optional(Box::new(self.resolve_type_node(&ta.args[0])))
|
PbsType::Optional(Box::new(self.resolve_type_node(&ta.args[0])))
|
||||||
@ -770,7 +785,7 @@ impl<'a> TypeChecker<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup_type(&self, name: &str) -> Option<&Symbol> {
|
fn lookup_type(&self, name: NameId) -> Option<&Symbol> {
|
||||||
if let Some(sym) = self.module_symbols.type_symbols.get(name) {
|
if let Some(sym) = self.module_symbols.type_symbols.get(name) {
|
||||||
return Some(sym);
|
return Some(sym);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ use crate::common::diagnostics::DiagnosticBundle;
|
|||||||
use crate::common::files::FileManager;
|
use crate::common::files::FileManager;
|
||||||
use crate::frontends::pbs::{collector::SymbolCollector, parser::Parser, Symbol, Visibility};
|
use crate::frontends::pbs::{collector::SymbolCollector, parser::Parser, Symbol, Visibility};
|
||||||
use crate::manifest::{load_manifest, ManifestKind};
|
use crate::manifest::{load_manifest, ManifestKind};
|
||||||
|
use prometeu_analysis::NameInterner;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
@ -118,6 +119,7 @@ fn discover_recursive(dir: &Path, files: &mut Vec<PathBuf>) -> std::io::Result<(
|
|||||||
pub fn build_exports(module_dir: &Path, file_manager: &mut FileManager) -> Result<ExportTable, SourceError> {
|
pub fn build_exports(module_dir: &Path, file_manager: &mut FileManager) -> Result<ExportTable, SourceError> {
|
||||||
let mut symbols = HashMap::new();
|
let mut symbols = HashMap::new();
|
||||||
let mut files = Vec::new();
|
let mut files = Vec::new();
|
||||||
|
let mut interner = NameInterner::new();
|
||||||
|
|
||||||
if module_dir.is_dir() {
|
if module_dir.is_dir() {
|
||||||
discover_recursive(module_dir, &mut files)?;
|
discover_recursive(module_dir, &mut files)?;
|
||||||
@ -129,21 +131,21 @@ pub fn build_exports(module_dir: &Path, file_manager: &mut FileManager) -> Resul
|
|||||||
let source = fs::read_to_string(&file_path)?;
|
let source = fs::read_to_string(&file_path)?;
|
||||||
let file_id = file_manager.add(file_path.clone(), source.clone());
|
let file_id = file_manager.add(file_path.clone(), source.clone());
|
||||||
|
|
||||||
let mut parser = Parser::new(&source, file_id);
|
let mut parser = Parser::new(&source, file_id, &mut interner);
|
||||||
let ast = parser.parse_file()?;
|
let ast = parser.parse_file()?;
|
||||||
|
|
||||||
let mut collector = SymbolCollector::new();
|
let mut collector = SymbolCollector::new(&interner);
|
||||||
let (type_symbols, value_symbols) = collector.collect(&ast)?;
|
let (type_symbols, value_symbols) = collector.collect(&ast)?;
|
||||||
|
|
||||||
// Merge only public symbols
|
// Merge only public symbols
|
||||||
for symbol in type_symbols.symbols.into_values() {
|
for symbol in type_symbols.symbols.into_values() {
|
||||||
if symbol.visibility == Visibility::Pub {
|
if symbol.visibility == Visibility::Pub {
|
||||||
symbols.insert(symbol.name.clone(), symbol);
|
symbols.insert(interner.resolve(symbol.name).to_string(), symbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for symbol in value_symbols.symbols.into_values() {
|
for symbol in value_symbols.symbols.into_values() {
|
||||||
if symbol.visibility == Visibility::Pub {
|
if symbol.visibility == Visibility::Pub {
|
||||||
symbols.insert(symbol.name.clone(), symbol);
|
symbols.insert(interner.resolve(symbol.name).to_string(), symbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ use prometeu_bytecode::BytecodeLoader;
|
|||||||
use prometeu_compiler::compiler::compile;
|
use prometeu_compiler::compiler::compile;
|
||||||
use prometeu_compiler::frontends::pbs::ast::Node;
|
use prometeu_compiler::frontends::pbs::ast::Node;
|
||||||
use prometeu_compiler::frontends::pbs::parser::Parser;
|
use prometeu_compiler::frontends::pbs::parser::Parser;
|
||||||
|
use prometeu_analysis::NameInterner;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
@ -56,7 +57,8 @@ fn generate_canonical_goldens() {
|
|||||||
|
|
||||||
// 3. AST JSON
|
// 3. AST JSON
|
||||||
let source = fs::read_to_string(project_dir.join("src/main/modules/main.pbs")).unwrap();
|
let source = fs::read_to_string(project_dir.join("src/main/modules/main.pbs")).unwrap();
|
||||||
let mut parser = Parser::new(&source, 0);
|
let mut interner = NameInterner::new();
|
||||||
|
let mut parser = Parser::new(&source, 0, &mut interner);
|
||||||
let ast = parser.parse_file().expect("Failed to parse AST");
|
let ast = parser.parse_file().expect("Failed to parse AST");
|
||||||
let ast_node = Node::File(ast);
|
let ast_node = Node::File(ast);
|
||||||
let ast_json = serde_json::to_string_pretty(&ast_node).unwrap();
|
let ast_json = serde_json::to_string_pretty(&ast_node).unwrap();
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
},
|
},
|
||||||
"vis": null,
|
"vis": null,
|
||||||
"type_kind": "struct",
|
"type_kind": "struct",
|
||||||
"name": "Color",
|
"name": 11,
|
||||||
"is_host": false,
|
"is_host": false,
|
||||||
"params": [
|
"params": [
|
||||||
{
|
{
|
||||||
@ -25,7 +25,7 @@
|
|||||||
"start": 100,
|
"start": 100,
|
||||||
"end": 112
|
"end": 112
|
||||||
},
|
},
|
||||||
"name": "raw",
|
"name": 12,
|
||||||
"ty": {
|
"ty": {
|
||||||
"kind": "TypeName",
|
"kind": "TypeName",
|
||||||
"span": {
|
"span": {
|
||||||
@ -33,7 +33,7 @@
|
|||||||
"start": 105,
|
"start": 105,
|
||||||
"end": 112
|
"end": 112
|
||||||
},
|
},
|
||||||
"name": "bounded"
|
"name": 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -45,7 +45,7 @@
|
|||||||
"start": 119,
|
"start": 119,
|
||||||
"end": 135
|
"end": 135
|
||||||
},
|
},
|
||||||
"name": "BLACK",
|
"name": 13,
|
||||||
"value": {
|
"value": {
|
||||||
"kind": "Call",
|
"kind": "Call",
|
||||||
"span": {
|
"span": {
|
||||||
@ -60,7 +60,7 @@
|
|||||||
"start": 126,
|
"start": 126,
|
||||||
"end": 131
|
"end": 131
|
||||||
},
|
},
|
||||||
"name": "Color"
|
"name": 11
|
||||||
},
|
},
|
||||||
"args": [
|
"args": [
|
||||||
{
|
{
|
||||||
@ -81,7 +81,7 @@
|
|||||||
"start": 139,
|
"start": 139,
|
||||||
"end": 159
|
"end": 159
|
||||||
},
|
},
|
||||||
"name": "WHITE",
|
"name": 14,
|
||||||
"value": {
|
"value": {
|
||||||
"kind": "Call",
|
"kind": "Call",
|
||||||
"span": {
|
"span": {
|
||||||
@ -96,7 +96,7 @@
|
|||||||
"start": 146,
|
"start": 146,
|
||||||
"end": 151
|
"end": 151
|
||||||
},
|
},
|
||||||
"name": "Color"
|
"name": 11
|
||||||
},
|
},
|
||||||
"args": [
|
"args": [
|
||||||
{
|
{
|
||||||
@ -117,7 +117,7 @@
|
|||||||
"start": 163,
|
"start": 163,
|
||||||
"end": 181
|
"end": 181
|
||||||
},
|
},
|
||||||
"name": "RED",
|
"name": 15,
|
||||||
"value": {
|
"value": {
|
||||||
"kind": "Call",
|
"kind": "Call",
|
||||||
"span": {
|
"span": {
|
||||||
@ -132,7 +132,7 @@
|
|||||||
"start": 168,
|
"start": 168,
|
||||||
"end": 173
|
"end": 173
|
||||||
},
|
},
|
||||||
"name": "Color"
|
"name": 11
|
||||||
},
|
},
|
||||||
"args": [
|
"args": [
|
||||||
{
|
{
|
||||||
@ -153,7 +153,7 @@
|
|||||||
"start": 185,
|
"start": 185,
|
||||||
"end": 204
|
"end": 204
|
||||||
},
|
},
|
||||||
"name": "GREEN",
|
"name": 16,
|
||||||
"value": {
|
"value": {
|
||||||
"kind": "Call",
|
"kind": "Call",
|
||||||
"span": {
|
"span": {
|
||||||
@ -168,7 +168,7 @@
|
|||||||
"start": 192,
|
"start": 192,
|
||||||
"end": 197
|
"end": 197
|
||||||
},
|
},
|
||||||
"name": "Color"
|
"name": 11
|
||||||
},
|
},
|
||||||
"args": [
|
"args": [
|
||||||
{
|
{
|
||||||
@ -189,7 +189,7 @@
|
|||||||
"start": 208,
|
"start": 208,
|
||||||
"end": 224
|
"end": 224
|
||||||
},
|
},
|
||||||
"name": "BLUE",
|
"name": 17,
|
||||||
"value": {
|
"value": {
|
||||||
"kind": "Call",
|
"kind": "Call",
|
||||||
"span": {
|
"span": {
|
||||||
@ -204,7 +204,7 @@
|
|||||||
"start": 214,
|
"start": 214,
|
||||||
"end": 219
|
"end": 219
|
||||||
},
|
},
|
||||||
"name": "Color"
|
"name": 11
|
||||||
},
|
},
|
||||||
"args": [
|
"args": [
|
||||||
{
|
{
|
||||||
@ -231,7 +231,7 @@
|
|||||||
},
|
},
|
||||||
"vis": null,
|
"vis": null,
|
||||||
"type_kind": "struct",
|
"type_kind": "struct",
|
||||||
"name": "ButtonState",
|
"name": 18,
|
||||||
"is_host": false,
|
"is_host": false,
|
||||||
"params": [
|
"params": [
|
||||||
{
|
{
|
||||||
@ -240,7 +240,7 @@
|
|||||||
"start": 261,
|
"start": 261,
|
||||||
"end": 274
|
"end": 274
|
||||||
},
|
},
|
||||||
"name": "pressed",
|
"name": 19,
|
||||||
"ty": {
|
"ty": {
|
||||||
"kind": "TypeName",
|
"kind": "TypeName",
|
||||||
"span": {
|
"span": {
|
||||||
@ -248,7 +248,7 @@
|
|||||||
"start": 270,
|
"start": 270,
|
||||||
"end": 274
|
"end": 274
|
||||||
},
|
},
|
||||||
"name": "bool"
|
"name": 20
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -257,7 +257,7 @@
|
|||||||
"start": 280,
|
"start": 280,
|
||||||
"end": 294
|
"end": 294
|
||||||
},
|
},
|
||||||
"name": "released",
|
"name": 21,
|
||||||
"ty": {
|
"ty": {
|
||||||
"kind": "TypeName",
|
"kind": "TypeName",
|
||||||
"span": {
|
"span": {
|
||||||
@ -265,7 +265,7 @@
|
|||||||
"start": 290,
|
"start": 290,
|
||||||
"end": 294
|
"end": 294
|
||||||
},
|
},
|
||||||
"name": "bool"
|
"name": 20
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -274,7 +274,7 @@
|
|||||||
"start": 300,
|
"start": 300,
|
||||||
"end": 310
|
"end": 310
|
||||||
},
|
},
|
||||||
"name": "down",
|
"name": 22,
|
||||||
"ty": {
|
"ty": {
|
||||||
"kind": "TypeName",
|
"kind": "TypeName",
|
||||||
"span": {
|
"span": {
|
||||||
@ -282,7 +282,7 @@
|
|||||||
"start": 306,
|
"start": 306,
|
||||||
"end": 310
|
"end": 310
|
||||||
},
|
},
|
||||||
"name": "bool"
|
"name": 20
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -291,7 +291,7 @@
|
|||||||
"start": 316,
|
"start": 316,
|
||||||
"end": 336
|
"end": 336
|
||||||
},
|
},
|
||||||
"name": "hold_frames",
|
"name": 23,
|
||||||
"ty": {
|
"ty": {
|
||||||
"kind": "TypeName",
|
"kind": "TypeName",
|
||||||
"span": {
|
"span": {
|
||||||
@ -299,7 +299,7 @@
|
|||||||
"start": 329,
|
"start": 329,
|
||||||
"end": 336
|
"end": 336
|
||||||
},
|
},
|
||||||
"name": "bounded"
|
"name": 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -316,7 +316,7 @@
|
|||||||
},
|
},
|
||||||
"vis": null,
|
"vis": null,
|
||||||
"type_kind": "struct",
|
"type_kind": "struct",
|
||||||
"name": "Pad",
|
"name": 24,
|
||||||
"is_host": false,
|
"is_host": false,
|
||||||
"params": [
|
"params": [
|
||||||
{
|
{
|
||||||
@ -325,7 +325,7 @@
|
|||||||
"start": 364,
|
"start": 364,
|
||||||
"end": 379
|
"end": 379
|
||||||
},
|
},
|
||||||
"name": "up",
|
"name": 25,
|
||||||
"ty": {
|
"ty": {
|
||||||
"kind": "TypeName",
|
"kind": "TypeName",
|
||||||
"span": {
|
"span": {
|
||||||
@ -333,7 +333,7 @@
|
|||||||
"start": 368,
|
"start": 368,
|
||||||
"end": 379
|
"end": 379
|
||||||
},
|
},
|
||||||
"name": "ButtonState"
|
"name": 18
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -342,7 +342,7 @@
|
|||||||
"start": 385,
|
"start": 385,
|
||||||
"end": 402
|
"end": 402
|
||||||
},
|
},
|
||||||
"name": "down",
|
"name": 22,
|
||||||
"ty": {
|
"ty": {
|
||||||
"kind": "TypeName",
|
"kind": "TypeName",
|
||||||
"span": {
|
"span": {
|
||||||
@ -350,7 +350,7 @@
|
|||||||
"start": 391,
|
"start": 391,
|
||||||
"end": 402
|
"end": 402
|
||||||
},
|
},
|
||||||
"name": "ButtonState"
|
"name": 18
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -359,7 +359,7 @@
|
|||||||
"start": 408,
|
"start": 408,
|
||||||
"end": 425
|
"end": 425
|
||||||
},
|
},
|
||||||
"name": "left",
|
"name": 26,
|
||||||
"ty": {
|
"ty": {
|
||||||
"kind": "TypeName",
|
"kind": "TypeName",
|
||||||
"span": {
|
"span": {
|
||||||
@ -367,7 +367,7 @@
|
|||||||
"start": 414,
|
"start": 414,
|
||||||
"end": 425
|
"end": 425
|
||||||
},
|
},
|
||||||
"name": "ButtonState"
|
"name": 18
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -376,7 +376,7 @@
|
|||||||
"start": 431,
|
"start": 431,
|
||||||
"end": 449
|
"end": 449
|
||||||
},
|
},
|
||||||
"name": "right",
|
"name": 27,
|
||||||
"ty": {
|
"ty": {
|
||||||
"kind": "TypeName",
|
"kind": "TypeName",
|
||||||
"span": {
|
"span": {
|
||||||
@ -384,7 +384,7 @@
|
|||||||
"start": 438,
|
"start": 438,
|
||||||
"end": 449
|
"end": 449
|
||||||
},
|
},
|
||||||
"name": "ButtonState"
|
"name": 18
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -393,7 +393,7 @@
|
|||||||
"start": 455,
|
"start": 455,
|
||||||
"end": 469
|
"end": 469
|
||||||
},
|
},
|
||||||
"name": "a",
|
"name": 28,
|
||||||
"ty": {
|
"ty": {
|
||||||
"kind": "TypeName",
|
"kind": "TypeName",
|
||||||
"span": {
|
"span": {
|
||||||
@ -401,7 +401,7 @@
|
|||||||
"start": 458,
|
"start": 458,
|
||||||
"end": 469
|
"end": 469
|
||||||
},
|
},
|
||||||
"name": "ButtonState"
|
"name": 18
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -410,7 +410,7 @@
|
|||||||
"start": 475,
|
"start": 475,
|
||||||
"end": 489
|
"end": 489
|
||||||
},
|
},
|
||||||
"name": "b",
|
"name": 29,
|
||||||
"ty": {
|
"ty": {
|
||||||
"kind": "TypeName",
|
"kind": "TypeName",
|
||||||
"span": {
|
"span": {
|
||||||
@ -418,7 +418,7 @@
|
|||||||
"start": 478,
|
"start": 478,
|
||||||
"end": 489
|
"end": 489
|
||||||
},
|
},
|
||||||
"name": "ButtonState"
|
"name": 18
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -427,7 +427,7 @@
|
|||||||
"start": 495,
|
"start": 495,
|
||||||
"end": 509
|
"end": 509
|
||||||
},
|
},
|
||||||
"name": "x",
|
"name": 30,
|
||||||
"ty": {
|
"ty": {
|
||||||
"kind": "TypeName",
|
"kind": "TypeName",
|
||||||
"span": {
|
"span": {
|
||||||
@ -435,7 +435,7 @@
|
|||||||
"start": 498,
|
"start": 498,
|
||||||
"end": 509
|
"end": 509
|
||||||
},
|
},
|
||||||
"name": "ButtonState"
|
"name": 18
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -444,7 +444,7 @@
|
|||||||
"start": 515,
|
"start": 515,
|
||||||
"end": 529
|
"end": 529
|
||||||
},
|
},
|
||||||
"name": "y",
|
"name": 31,
|
||||||
"ty": {
|
"ty": {
|
||||||
"kind": "TypeName",
|
"kind": "TypeName",
|
||||||
"span": {
|
"span": {
|
||||||
@ -452,7 +452,7 @@
|
|||||||
"start": 518,
|
"start": 518,
|
||||||
"end": 529
|
"end": 529
|
||||||
},
|
},
|
||||||
"name": "ButtonState"
|
"name": 18
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -461,7 +461,7 @@
|
|||||||
"start": 535,
|
"start": 535,
|
||||||
"end": 549
|
"end": 549
|
||||||
},
|
},
|
||||||
"name": "l",
|
"name": 32,
|
||||||
"ty": {
|
"ty": {
|
||||||
"kind": "TypeName",
|
"kind": "TypeName",
|
||||||
"span": {
|
"span": {
|
||||||
@ -469,7 +469,7 @@
|
|||||||
"start": 538,
|
"start": 538,
|
||||||
"end": 549
|
"end": 549
|
||||||
},
|
},
|
||||||
"name": "ButtonState"
|
"name": 18
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -478,7 +478,7 @@
|
|||||||
"start": 555,
|
"start": 555,
|
||||||
"end": 569
|
"end": 569
|
||||||
},
|
},
|
||||||
"name": "r",
|
"name": 33,
|
||||||
"ty": {
|
"ty": {
|
||||||
"kind": "TypeName",
|
"kind": "TypeName",
|
||||||
"span": {
|
"span": {
|
||||||
@ -486,7 +486,7 @@
|
|||||||
"start": 558,
|
"start": 558,
|
||||||
"end": 569
|
"end": 569
|
||||||
},
|
},
|
||||||
"name": "ButtonState"
|
"name": 18
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -495,7 +495,7 @@
|
|||||||
"start": 575,
|
"start": 575,
|
||||||
"end": 593
|
"end": 593
|
||||||
},
|
},
|
||||||
"name": "start",
|
"name": 34,
|
||||||
"ty": {
|
"ty": {
|
||||||
"kind": "TypeName",
|
"kind": "TypeName",
|
||||||
"span": {
|
"span": {
|
||||||
@ -503,7 +503,7 @@
|
|||||||
"start": 582,
|
"start": 582,
|
||||||
"end": 593
|
"end": 593
|
||||||
},
|
},
|
||||||
"name": "ButtonState"
|
"name": 18
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -512,7 +512,7 @@
|
|||||||
"start": 599,
|
"start": 599,
|
||||||
"end": 618
|
"end": 618
|
||||||
},
|
},
|
||||||
"name": "select",
|
"name": 35,
|
||||||
"ty": {
|
"ty": {
|
||||||
"kind": "TypeName",
|
"kind": "TypeName",
|
||||||
"span": {
|
"span": {
|
||||||
@ -520,7 +520,7 @@
|
|||||||
"start": 607,
|
"start": 607,
|
||||||
"end": 618
|
"end": 618
|
||||||
},
|
},
|
||||||
"name": "ButtonState"
|
"name": 18
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -537,7 +537,7 @@
|
|||||||
},
|
},
|
||||||
"vis": null,
|
"vis": null,
|
||||||
"type_kind": "contract",
|
"type_kind": "contract",
|
||||||
"name": "Gfx",
|
"name": 36,
|
||||||
"is_host": true,
|
"is_host": true,
|
||||||
"params": [],
|
"params": [],
|
||||||
"constructors": [],
|
"constructors": [],
|
||||||
@ -557,7 +557,7 @@
|
|||||||
"start": 654,
|
"start": 654,
|
||||||
"end": 682
|
"end": 682
|
||||||
},
|
},
|
||||||
"name": "clear",
|
"name": 37,
|
||||||
"params": [
|
"params": [
|
||||||
{
|
{
|
||||||
"span": {
|
"span": {
|
||||||
@ -565,7 +565,7 @@
|
|||||||
"start": 663,
|
"start": 663,
|
||||||
"end": 675
|
"end": 675
|
||||||
},
|
},
|
||||||
"name": "color",
|
"name": 38,
|
||||||
"ty": {
|
"ty": {
|
||||||
"kind": "TypeName",
|
"kind": "TypeName",
|
||||||
"span": {
|
"span": {
|
||||||
@ -573,7 +573,7 @@
|
|||||||
"start": 670,
|
"start": 670,
|
||||||
"end": 675
|
"end": 675
|
||||||
},
|
},
|
||||||
"name": "Color"
|
"name": 11
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -584,7 +584,7 @@
|
|||||||
"start": 678,
|
"start": 678,
|
||||||
"end": 682
|
"end": 682
|
||||||
},
|
},
|
||||||
"name": "void"
|
"name": 6
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -599,7 +599,7 @@
|
|||||||
},
|
},
|
||||||
"vis": null,
|
"vis": null,
|
||||||
"type_kind": "contract",
|
"type_kind": "contract",
|
||||||
"name": "Input",
|
"name": 39,
|
||||||
"is_host": true,
|
"is_host": true,
|
||||||
"params": [],
|
"params": [],
|
||||||
"constructors": [],
|
"constructors": [],
|
||||||
@ -619,7 +619,7 @@
|
|||||||
"start": 721,
|
"start": 721,
|
||||||
"end": 734
|
"end": 734
|
||||||
},
|
},
|
||||||
"name": "pad",
|
"name": 40,
|
||||||
"params": [],
|
"params": [],
|
||||||
"ret": {
|
"ret": {
|
||||||
"kind": "TypeName",
|
"kind": "TypeName",
|
||||||
@ -628,7 +628,7 @@
|
|||||||
"start": 731,
|
"start": 731,
|
||||||
"end": 734
|
"end": 734
|
||||||
},
|
},
|
||||||
"name": "Pad"
|
"name": 24
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -642,7 +642,7 @@
|
|||||||
"end": 788
|
"end": 788
|
||||||
},
|
},
|
||||||
"vis": null,
|
"vis": null,
|
||||||
"name": "add",
|
"name": 41,
|
||||||
"params": [
|
"params": [
|
||||||
{
|
{
|
||||||
"span": {
|
"span": {
|
||||||
@ -650,7 +650,7 @@
|
|||||||
"start": 746,
|
"start": 746,
|
||||||
"end": 752
|
"end": 752
|
||||||
},
|
},
|
||||||
"name": "a",
|
"name": 28,
|
||||||
"ty": {
|
"ty": {
|
||||||
"kind": "TypeName",
|
"kind": "TypeName",
|
||||||
"span": {
|
"span": {
|
||||||
@ -658,7 +658,7 @@
|
|||||||
"start": 749,
|
"start": 749,
|
||||||
"end": 752
|
"end": 752
|
||||||
},
|
},
|
||||||
"name": "int"
|
"name": 42
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -667,7 +667,7 @@
|
|||||||
"start": 754,
|
"start": 754,
|
||||||
"end": 760
|
"end": 760
|
||||||
},
|
},
|
||||||
"name": "b",
|
"name": 29,
|
||||||
"ty": {
|
"ty": {
|
||||||
"kind": "TypeName",
|
"kind": "TypeName",
|
||||||
"span": {
|
"span": {
|
||||||
@ -675,7 +675,7 @@
|
|||||||
"start": 757,
|
"start": 757,
|
||||||
"end": 760
|
"end": 760
|
||||||
},
|
},
|
||||||
"name": "int"
|
"name": 42
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -686,7 +686,7 @@
|
|||||||
"start": 763,
|
"start": 763,
|
||||||
"end": 766
|
"end": 766
|
||||||
},
|
},
|
||||||
"name": "int"
|
"name": 42
|
||||||
},
|
},
|
||||||
"else_fallback": null,
|
"else_fallback": null,
|
||||||
"body": {
|
"body": {
|
||||||
@ -719,7 +719,7 @@
|
|||||||
"start": 780,
|
"start": 780,
|
||||||
"end": 781
|
"end": 781
|
||||||
},
|
},
|
||||||
"name": "a"
|
"name": 28
|
||||||
},
|
},
|
||||||
"right": {
|
"right": {
|
||||||
"kind": "Ident",
|
"kind": "Ident",
|
||||||
@ -728,7 +728,7 @@
|
|||||||
"start": 784,
|
"start": 784,
|
||||||
"end": 785
|
"end": 785
|
||||||
},
|
},
|
||||||
"name": "b"
|
"name": 29
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -744,7 +744,7 @@
|
|||||||
"end": 1180
|
"end": 1180
|
||||||
},
|
},
|
||||||
"vis": null,
|
"vis": null,
|
||||||
"name": "frame",
|
"name": 43,
|
||||||
"params": [],
|
"params": [],
|
||||||
"ret": {
|
"ret": {
|
||||||
"kind": "TypeName",
|
"kind": "TypeName",
|
||||||
@ -753,7 +753,7 @@
|
|||||||
"start": 802,
|
"start": 802,
|
||||||
"end": 806
|
"end": 806
|
||||||
},
|
},
|
||||||
"name": "void"
|
"name": 6
|
||||||
},
|
},
|
||||||
"else_fallback": null,
|
"else_fallback": null,
|
||||||
"body": {
|
"body": {
|
||||||
@ -771,7 +771,7 @@
|
|||||||
"start": 843,
|
"start": 843,
|
||||||
"end": 854
|
"end": 854
|
||||||
},
|
},
|
||||||
"name": "x",
|
"name": 30,
|
||||||
"is_mut": false,
|
"is_mut": false,
|
||||||
"ty": null,
|
"ty": null,
|
||||||
"init": {
|
"init": {
|
||||||
@ -791,7 +791,7 @@
|
|||||||
"start": 859,
|
"start": 859,
|
||||||
"end": 870
|
"end": 870
|
||||||
},
|
},
|
||||||
"name": "y",
|
"name": 31,
|
||||||
"is_mut": false,
|
"is_mut": false,
|
||||||
"ty": null,
|
"ty": null,
|
||||||
"init": {
|
"init": {
|
||||||
@ -811,7 +811,7 @@
|
|||||||
"start": 875,
|
"start": 875,
|
||||||
"end": 893
|
"end": 893
|
||||||
},
|
},
|
||||||
"name": "z",
|
"name": 44,
|
||||||
"is_mut": false,
|
"is_mut": false,
|
||||||
"ty": null,
|
"ty": null,
|
||||||
"init": {
|
"init": {
|
||||||
@ -828,7 +828,7 @@
|
|||||||
"start": 883,
|
"start": 883,
|
||||||
"end": 886
|
"end": 886
|
||||||
},
|
},
|
||||||
"name": "add"
|
"name": 41
|
||||||
},
|
},
|
||||||
"args": [
|
"args": [
|
||||||
{
|
{
|
||||||
@ -838,7 +838,7 @@
|
|||||||
"start": 887,
|
"start": 887,
|
||||||
"end": 888
|
"end": 888
|
||||||
},
|
},
|
||||||
"name": "x"
|
"name": 30
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"kind": "Ident",
|
"kind": "Ident",
|
||||||
@ -847,7 +847,7 @@
|
|||||||
"start": 890,
|
"start": 890,
|
||||||
"end": 891
|
"end": 891
|
||||||
},
|
},
|
||||||
"name": "y"
|
"name": 31
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -881,7 +881,7 @@
|
|||||||
"start": 930,
|
"start": 930,
|
||||||
"end": 931
|
"end": 931
|
||||||
},
|
},
|
||||||
"name": "z"
|
"name": 44
|
||||||
},
|
},
|
||||||
"right": {
|
"right": {
|
||||||
"kind": "IntLit",
|
"kind": "IntLit",
|
||||||
@ -929,9 +929,9 @@
|
|||||||
"start": 976,
|
"start": 976,
|
||||||
"end": 979
|
"end": 979
|
||||||
},
|
},
|
||||||
"name": "Gfx"
|
"name": 36
|
||||||
},
|
},
|
||||||
"member": "clear"
|
"member": 37
|
||||||
},
|
},
|
||||||
"args": [
|
"args": [
|
||||||
{
|
{
|
||||||
@ -948,9 +948,9 @@
|
|||||||
"start": 986,
|
"start": 986,
|
||||||
"end": 991
|
"end": 991
|
||||||
},
|
},
|
||||||
"name": "Color"
|
"name": 11
|
||||||
},
|
},
|
||||||
"member": "GREEN"
|
"member": 16
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -994,9 +994,9 @@
|
|||||||
"start": 1022,
|
"start": 1022,
|
||||||
"end": 1025
|
"end": 1025
|
||||||
},
|
},
|
||||||
"name": "Gfx"
|
"name": 36
|
||||||
},
|
},
|
||||||
"member": "clear"
|
"member": 37
|
||||||
},
|
},
|
||||||
"args": [
|
"args": [
|
||||||
{
|
{
|
||||||
@ -1013,9 +1013,9 @@
|
|||||||
"start": 1032,
|
"start": 1032,
|
||||||
"end": 1037
|
"end": 1037
|
||||||
},
|
},
|
||||||
"name": "Color"
|
"name": 11
|
||||||
},
|
},
|
||||||
"member": "RED"
|
"member": 15
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -1032,7 +1032,7 @@
|
|||||||
"start": 1103,
|
"start": 1103,
|
||||||
"end": 1123
|
"end": 1123
|
||||||
},
|
},
|
||||||
"name": "p",
|
"name": 45,
|
||||||
"is_mut": false,
|
"is_mut": false,
|
||||||
"ty": null,
|
"ty": null,
|
||||||
"init": {
|
"init": {
|
||||||
@ -1056,9 +1056,9 @@
|
|||||||
"start": 1111,
|
"start": 1111,
|
||||||
"end": 1116
|
"end": 1116
|
||||||
},
|
},
|
||||||
"name": "Input"
|
"name": 39
|
||||||
},
|
},
|
||||||
"member": "pad"
|
"member": 40
|
||||||
},
|
},
|
||||||
"args": []
|
"args": []
|
||||||
}
|
}
|
||||||
@ -1092,11 +1092,11 @@
|
|||||||
"start": 1131,
|
"start": 1131,
|
||||||
"end": 1132
|
"end": 1132
|
||||||
},
|
},
|
||||||
"name": "p"
|
"name": 45
|
||||||
},
|
},
|
||||||
"member": "a"
|
"member": 28
|
||||||
},
|
},
|
||||||
"member": "down"
|
"member": 22
|
||||||
},
|
},
|
||||||
"then_block": {
|
"then_block": {
|
||||||
"kind": "Block",
|
"kind": "Block",
|
||||||
@ -1134,9 +1134,9 @@
|
|||||||
"start": 1150,
|
"start": 1150,
|
||||||
"end": 1153
|
"end": 1153
|
||||||
},
|
},
|
||||||
"name": "Gfx"
|
"name": 36
|
||||||
},
|
},
|
||||||
"member": "clear"
|
"member": 37
|
||||||
},
|
},
|
||||||
"args": [
|
"args": [
|
||||||
{
|
{
|
||||||
@ -1153,9 +1153,9 @@
|
|||||||
"start": 1160,
|
"start": 1160,
|
||||||
"end": 1165
|
"end": 1165
|
||||||
},
|
},
|
||||||
"name": "Color"
|
"name": 11
|
||||||
},
|
},
|
||||||
"member": "BLUE"
|
"member": 17
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user