Started AST
This commit is contained in:
parent
3f99fefe87
commit
1ab6bb1e2b
11
src/main.rs
11
src/main.rs
|
@ -10,7 +10,6 @@ use std::ops::Add;
|
|||
use err::*;
|
||||
use lookahead::*;
|
||||
use parse::*;
|
||||
use semantic::Analyzer;
|
||||
use token::*;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
|
@ -70,17 +69,7 @@ fn parse(input: &'static str) -> impl Iterator<Item = Statement> {
|
|||
Parser::new(tokenize(input))
|
||||
}
|
||||
|
||||
fn typecheck(input: &'static str) {
|
||||
let parsed: Vec<_> = parse(input).collect();
|
||||
let mut s = semantic::Analyzer::new();
|
||||
s.block(parsed);
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
for p in parse(include_str!("../demo.hal")) {
|
||||
println!("------------------");
|
||||
println!("{p:#?}");
|
||||
}
|
||||
/*
|
||||
for s in typecheck(include_str!("../demo.hal")) {
|
||||
println!("------------------");
|
||||
|
|
|
@ -7,7 +7,6 @@ pub struct Parameters {
|
|||
pub arity: usize,
|
||||
pub names: Vec<String>,
|
||||
pub type_names: Vec<String>,
|
||||
pub types: Vec<String>,
|
||||
}
|
||||
|
||||
impl Default for Parameters {
|
||||
|
@ -16,7 +15,6 @@ impl Default for Parameters {
|
|||
arity: 0,
|
||||
names: vec![],
|
||||
type_names: vec![],
|
||||
types: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -94,12 +92,16 @@ pub enum ExpressionKind {
|
|||
pub struct Expression {
|
||||
pub kind: ExpressionKind,
|
||||
pub span: Span,
|
||||
pub type_: Type,
|
||||
pub type_: UID,
|
||||
}
|
||||
|
||||
impl Expression {
|
||||
pub fn new(kind: ExpressionKind, span: Span, type_: Type) -> Self {
|
||||
Self { kind, span, type_ }
|
||||
pub fn new(kind: ExpressionKind, span: Span) -> Self {
|
||||
Self {
|
||||
kind,
|
||||
span,
|
||||
type_: "".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,7 +196,6 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
|||
child: child.into(),
|
||||
},
|
||||
span,
|
||||
Type::Ambiguous,
|
||||
)
|
||||
}
|
||||
// Primary
|
||||
|
@ -226,7 +227,6 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
|||
right: rhs.into(),
|
||||
},
|
||||
span,
|
||||
Type::Ambiguous,
|
||||
);
|
||||
}
|
||||
// Field
|
||||
|
@ -245,7 +245,6 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
|||
uid: "".into(),
|
||||
},
|
||||
span,
|
||||
Type::Ambiguous,
|
||||
)
|
||||
}
|
||||
// Function call
|
||||
|
@ -275,7 +274,6 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
|||
uid: "".into(),
|
||||
},
|
||||
span + span2,
|
||||
Type::Ambiguous,
|
||||
);
|
||||
}
|
||||
// Unary postfix
|
||||
|
@ -296,7 +294,6 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
|||
child: current.into(),
|
||||
},
|
||||
span,
|
||||
Type::Ambiguous,
|
||||
);
|
||||
} else {
|
||||
break;
|
||||
|
@ -310,7 +307,6 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
|||
let mut arity = 0;
|
||||
let mut names = vec![];
|
||||
let mut type_names = vec![];
|
||||
let mut types = vec![];
|
||||
let mut strongly_typed = false;
|
||||
loop {
|
||||
// Param name
|
||||
|
@ -333,7 +329,6 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
|||
} else {
|
||||
type_names.push("".into());
|
||||
}
|
||||
types.push("".into());
|
||||
arity += 1;
|
||||
// Comma
|
||||
if !self.eat(t::Comma).is_ok() {
|
||||
|
@ -368,7 +363,6 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
|||
arity,
|
||||
names,
|
||||
type_names,
|
||||
types,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -507,7 +501,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
|||
.reason(format!("Expected expression, found {}", next.0));
|
||||
},
|
||||
};
|
||||
Ok(Expression::new(kind, span, Type::Ambiguous))
|
||||
Ok(Expression::new(kind, span))
|
||||
}
|
||||
|
||||
fn if_else(&mut self) -> Result<Expression> {
|
||||
|
@ -526,22 +520,17 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
|||
} else {
|
||||
None
|
||||
};
|
||||
Ok(Expression {
|
||||
kind: ExpressionKind::If {
|
||||
Ok(Expression::new(
|
||||
ExpressionKind::If {
|
||||
predicate: predicate.into(),
|
||||
block,
|
||||
else_,
|
||||
},
|
||||
span,
|
||||
type_: Type::Ambiguous,
|
||||
})
|
||||
))
|
||||
} else {
|
||||
let (block, span) = self.block()?;
|
||||
Ok(Expression {
|
||||
kind: ExpressionKind::Block(block),
|
||||
span,
|
||||
type_: Type::Ambiguous,
|
||||
})
|
||||
Ok(Expression::new(ExpressionKind::Block(block), span))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,15 +7,12 @@ pub enum StatementKind {
|
|||
Declaration {
|
||||
name: String,
|
||||
type_str: Option<String>,
|
||||
type_uid: UID,
|
||||
value: Expression,
|
||||
mutable: bool,
|
||||
uid: UID,
|
||||
},
|
||||
Assignment {
|
||||
name: String,
|
||||
value: Expression,
|
||||
uid: UID,
|
||||
},
|
||||
While {
|
||||
predicate: Expression,
|
||||
|
@ -78,10 +75,8 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
|||
kind: s::Declaration {
|
||||
name,
|
||||
type_str,
|
||||
type_uid: "".into(),
|
||||
value,
|
||||
mutable,
|
||||
uid: "".into(),
|
||||
},
|
||||
span,
|
||||
};
|
||||
|
@ -99,11 +94,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
|||
.trace_span(span, "while parsing assignment")?;
|
||||
Statement {
|
||||
span,
|
||||
kind: s::Assignment {
|
||||
name,
|
||||
value,
|
||||
uid: "".into(),
|
||||
},
|
||||
kind: s::Assignment { name, value },
|
||||
}
|
||||
},
|
||||
// While
|
||||
|
|
|
@ -1,91 +1,3 @@
|
|||
use crate::{Expression, ExpressionKind, Statement, StatementKind};
|
||||
|
||||
use super::*;
|
||||
|
||||
pub struct Analyzer {
|
||||
table: SymbolTable,
|
||||
}
|
||||
|
||||
impl Analyzer {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
table: SymbolTable::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn typecheck() {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Analyzing a block:
|
||||
/// 1. Name structs
|
||||
/// 2. Type structs
|
||||
/// 3. Name and type functions
|
||||
/// 4. Name variables (recurse on blocks) (track moves)
|
||||
/// 5. Type variables
|
||||
/// 6. Type assert variables
|
||||
pub fn block(&mut self, mut block: Vec<Statement>) -> Result<Vec<Statement>> {
|
||||
// 1. Name structs
|
||||
for s in &mut block {
|
||||
if let StatementKind::Declaration {
|
||||
name,
|
||||
value:
|
||||
Expression {
|
||||
kind: ExpressionKind::StructDef(params, _),
|
||||
type_,
|
||||
..
|
||||
},
|
||||
..
|
||||
} = &mut s.kind
|
||||
{
|
||||
*type_ = Type::Nothing;
|
||||
self.table.declare_struct(name, s.span)?;
|
||||
}
|
||||
}
|
||||
// 2. Type structs
|
||||
for s in &mut block {
|
||||
if let StatementKind::Declaration {
|
||||
name,
|
||||
value:
|
||||
Expression {
|
||||
kind: ExpressionKind::StructDef(params, _),
|
||||
..
|
||||
},
|
||||
..
|
||||
} = &mut s.kind
|
||||
{
|
||||
self.table.declare_struct(name, s.span)?;
|
||||
}
|
||||
}
|
||||
// 3. Name and type functions
|
||||
for s in &mut block {
|
||||
if let StatementKind::Declaration {
|
||||
name,
|
||||
value:
|
||||
Expression {
|
||||
kind:
|
||||
ExpressionKind::FunctionDef {
|
||||
params,
|
||||
returns_str,
|
||||
returns_actual,
|
||||
body,
|
||||
uid,
|
||||
},
|
||||
type_,
|
||||
span,
|
||||
},
|
||||
..
|
||||
} = &mut s.kind
|
||||
{
|
||||
let uid = self.table.define_function(
|
||||
name,
|
||||
params.clone(),
|
||||
returns_str.as_ref().map(|s| s.as_str()),
|
||||
*span,
|
||||
)?;
|
||||
*type_ = Type::Function(uid);
|
||||
}
|
||||
}
|
||||
Ok(block)
|
||||
}
|
||||
}
|
||||
|
|
24
src/semantic/builtin.rs
Normal file
24
src/semantic/builtin.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
use super::{UID, primitives::Primitive};
|
||||
|
||||
pub fn mangle(input: &str) -> UID {
|
||||
format!("$${input}")
|
||||
}
|
||||
|
||||
// Nothing ever happens
|
||||
pub fn nothing() -> UID {
|
||||
mangle("nothing")
|
||||
}
|
||||
|
||||
pub fn integer() -> UID {
|
||||
Primitive::integer_ambiguous.mangle()
|
||||
}
|
||||
|
||||
pub fn real() -> UID {
|
||||
Primitive::real_ambiguous.mangle()
|
||||
}
|
||||
|
||||
pub fn all() -> Vec<UID> {
|
||||
let mut uids = Primitive::ALL.map(|p| p.mangle()).to_vec();
|
||||
uids.push(nothing());
|
||||
uids
|
||||
}
|
|
@ -1,12 +1,10 @@
|
|||
pub mod analyzer;
|
||||
mod builtin;
|
||||
pub mod primitives;
|
||||
|
||||
pub use analyzer::*;
|
||||
pub use primitives::*;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{Parameters, Span, err::*, semantic::Primitive};
|
||||
use crate::{BinaryOp, UnaryOp, semantic::Primitive};
|
||||
|
||||
pub type UID = String;
|
||||
|
||||
|
@ -15,6 +13,7 @@ pub enum Type {
|
|||
Ambiguous,
|
||||
Prim(Primitive),
|
||||
Nothing,
|
||||
Never,
|
||||
Struct(UID),
|
||||
Function(UID),
|
||||
}
|
||||
|
@ -27,331 +26,50 @@ impl std::fmt::Display for Type {
|
|||
Type::Nothing => write!(f, "nothing"),
|
||||
Type::Struct(s) => write!(f, "struct {s}"),
|
||||
Type::Function(func) => write!(f, "func {func}"),
|
||||
Type::Never => write!(f, "never"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SymbolKind {
|
||||
Variable {
|
||||
type_: UID,
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct IrBlock {
|
||||
nodes: Vec<IrNode>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum IrNode {
|
||||
Declaration {
|
||||
uid: UID,
|
||||
mutable: bool,
|
||||
global: bool,
|
||||
children: Vec<UID>,
|
||||
size: usize,
|
||||
value: IrExpr,
|
||||
},
|
||||
Function {
|
||||
params: Parameters,
|
||||
returns: UID,
|
||||
uid: UID,
|
||||
parameters: Vec<Type>,
|
||||
block: IrBlock,
|
||||
},
|
||||
Struct {
|
||||
params: Parameters,
|
||||
size: usize,
|
||||
align: usize,
|
||||
Conditional {
|
||||
branches: Vec<(IrExpr, IrBlock)>,
|
||||
default: IrBlock,
|
||||
},
|
||||
TypeDef {
|
||||
actual: Type,
|
||||
Expr(IrExpr),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum IrExpr {
|
||||
Ident(UID),
|
||||
UnOp {
|
||||
op: UnaryOp,
|
||||
child: Box<IrExpr>,
|
||||
},
|
||||
BinOp {
|
||||
op: BinaryOp,
|
||||
left: Box<IrExpr>,
|
||||
right: Box<IrExpr>,
|
||||
},
|
||||
Call {
|
||||
function: UID,
|
||||
args: Vec<IrExpr>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Symbol {
|
||||
pub name: String,
|
||||
pub uid: UID,
|
||||
pub span: Option<Span>,
|
||||
pub kind: SymbolKind,
|
||||
}
|
||||
|
||||
impl Symbol {
|
||||
pub fn is_variable(&self) -> Result<()> {
|
||||
let name = &self.name;
|
||||
match &self.kind {
|
||||
SymbolKind::Variable { .. } => Ok(()),
|
||||
SymbolKind::Function { .. } => {
|
||||
error().reason(format!("'{name}' refers to a function, not a value"))
|
||||
},
|
||||
_ => error().reason(format!("'{name}' refers to a type, not a value")),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_type(&self) -> Result<Type> {
|
||||
let name = &self.name;
|
||||
match &self.kind {
|
||||
SymbolKind::Struct { .. } => Ok(Type::Struct(self.uid.clone())),
|
||||
SymbolKind::TypeDef { actual } => Ok(actual.clone()),
|
||||
_ => error().reason(format!("'{name}' refers to a value, not a type")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Event {
|
||||
Declared { name: String, uid: UID },
|
||||
Moved { name: String, uid: UID, span: Span },
|
||||
Func { returns: Vec<UID>, uid: UID },
|
||||
Block { returns: UID },
|
||||
}
|
||||
|
||||
pub struct SymbolTable {
|
||||
syms: HashMap<UID, Symbol>,
|
||||
scope: Vec<Event>,
|
||||
nesting: usize,
|
||||
mangle_num: usize,
|
||||
}
|
||||
|
||||
impl SymbolTable {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
syms: HashMap::new(),
|
||||
scope: vec![],
|
||||
nesting: 0,
|
||||
mangle_num: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_uid(&mut self, name: &str) -> UID {
|
||||
let uid = format!("${}${name}", self.mangle_num);
|
||||
self.mangle_num += 1;
|
||||
uid
|
||||
}
|
||||
|
||||
pub fn get(&self, uid: &UID) -> &Symbol {
|
||||
self.syms.get(uid).unwrap()
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, uid: &UID) -> &mut Symbol {
|
||||
self.syms.get_mut(uid).unwrap()
|
||||
}
|
||||
|
||||
// Find the definition of a symbol in local and global scope
|
||||
pub fn find(&self, name: &str) -> Result<&Symbol> {
|
||||
let mut nesting = self.nesting;
|
||||
for e in self.scope.iter().rev() {
|
||||
match e {
|
||||
Event::Declared { uid, .. }
|
||||
if nesting == self.nesting || nesting == 0 =>
|
||||
{
|
||||
return Ok(self.get(uid));
|
||||
},
|
||||
Event::Moved { name, span, .. }
|
||||
if nesting == self.nesting || nesting == 0 =>
|
||||
{
|
||||
return error()
|
||||
.reason(format!("Symbol '{name}' moved out of scope here"))
|
||||
.span(&span);
|
||||
},
|
||||
Event::Func { .. } => {
|
||||
nesting -= 1;
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
error().reason(format!("Cannot find symbol '{name}'"))
|
||||
}
|
||||
|
||||
// Get all nested members of a struct variable
|
||||
fn get_all_children(&self, uid: &UID) -> Vec<UID> {
|
||||
use SymbolKind as s;
|
||||
match &self.get(uid).kind {
|
||||
s::Variable { children, .. } => {
|
||||
let mut new_children = children.clone();
|
||||
for uid in children {
|
||||
new_children.append(&mut self.get_all_children(uid))
|
||||
}
|
||||
new_children
|
||||
},
|
||||
_ => {
|
||||
vec![]
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Move a symbol out of scope
|
||||
pub fn move_symbol(&mut self, move_uid: &UID, span: Span) -> Result<()> {
|
||||
if let SymbolKind::Variable { global, .. } = self.get(move_uid).kind {
|
||||
if global {
|
||||
return error().reason("Cannot move global symbol").span(&span);
|
||||
}
|
||||
} else {
|
||||
panic!("Moved non-variable {move_uid}");
|
||||
}
|
||||
let children = self.get_all_children(move_uid);
|
||||
for e in self.scope.iter().rev() {
|
||||
match e {
|
||||
Event::Declared { uid, .. } => {
|
||||
if move_uid == uid {
|
||||
break;
|
||||
}
|
||||
},
|
||||
Event::Moved { uid, span, .. } => {
|
||||
if children.contains(uid) {
|
||||
return error()
|
||||
.reason("Symbol was partially moved here")
|
||||
.span(&span);
|
||||
} else if move_uid == uid {
|
||||
return error()
|
||||
.reason("Symbol was previously moved here")
|
||||
.span(&span);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
self.scope.push(Event::Moved {
|
||||
name: self.get(move_uid).name.clone(),
|
||||
uid: move_uid.clone(),
|
||||
span,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn in_global_scope(&self) -> bool {
|
||||
for e in self.scope.iter().rev() {
|
||||
if let Event::Func { .. } = e {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn define_var(
|
||||
&mut self,
|
||||
name: &str,
|
||||
mutable: bool,
|
||||
type_: &UID,
|
||||
span: Span,
|
||||
) -> UID {
|
||||
let uid = self.generate_uid(name);
|
||||
self.syms.insert(uid.clone(), Symbol {
|
||||
name: name.to_string(),
|
||||
span: Some(span),
|
||||
uid: uid.clone(),
|
||||
kind: SymbolKind::Variable {
|
||||
type_: type_.clone(),
|
||||
mutable,
|
||||
global: self.in_global_scope(),
|
||||
children: vec![],
|
||||
},
|
||||
});
|
||||
self.scope.push(Event::Declared {
|
||||
name: name.to_string(),
|
||||
uid: uid.clone(),
|
||||
});
|
||||
uid
|
||||
}
|
||||
|
||||
pub fn declare_struct(
|
||||
&mut self,
|
||||
struct_name: &str,
|
||||
span: Span,
|
||||
) -> Result<UID> {
|
||||
// Check for multiple definition
|
||||
for e in self.scope.iter().rev() {
|
||||
match e {
|
||||
Event::Declared { name, uid } => {
|
||||
if name == struct_name {
|
||||
let e = error().reason(format!(
|
||||
"Structure '{struct_name}' is defined multiple times"
|
||||
));
|
||||
if let Some(s) = &self.get(uid).span {
|
||||
return e.span(s);
|
||||
} else {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
},
|
||||
Event::Moved { .. } => {},
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
let uid = self.generate_uid(struct_name);
|
||||
self.syms.insert(uid.clone(), Symbol {
|
||||
name: struct_name.to_string(),
|
||||
uid: uid.clone(),
|
||||
span: Some(span),
|
||||
kind: SymbolKind::Struct {
|
||||
params: Parameters::default(),
|
||||
size: 0,
|
||||
align: 0,
|
||||
},
|
||||
});
|
||||
self.scope.push(Event::Declared {
|
||||
name: struct_name.to_string(),
|
||||
uid: uid.clone(),
|
||||
});
|
||||
Ok(uid)
|
||||
}
|
||||
|
||||
fn type_params(&mut self, mut params: Parameters) -> Result<Parameters> {
|
||||
for i in 0..params.arity {
|
||||
params.types[i] = self
|
||||
.find(¶ms.type_names[i])
|
||||
.trace(format!(
|
||||
"while resolving type of field '{}'",
|
||||
params.type_names[i]
|
||||
))?
|
||||
.uid
|
||||
.clone();
|
||||
}
|
||||
Ok(params)
|
||||
}
|
||||
|
||||
pub fn define_function(
|
||||
&mut self,
|
||||
func_name: &str,
|
||||
params: Parameters,
|
||||
returns_str: Option<&str>,
|
||||
span: Span,
|
||||
) -> Result<UID> {
|
||||
// Check for multiple definition
|
||||
for e in self.scope.iter().rev() {
|
||||
match e {
|
||||
Event::Declared { name, uid } => {
|
||||
if name == func_name {
|
||||
let e = error().reason(format!(
|
||||
"Function '{func_name}' is defined multiple times"
|
||||
));
|
||||
if let Some(s) = &self.get(uid).span {
|
||||
return e.span(s);
|
||||
} else {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
},
|
||||
Event::Moved { .. } => {},
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
let uid = self.generate_uid(func_name);
|
||||
// Check types
|
||||
let params = self.type_params(params)?;
|
||||
let returns = {
|
||||
let sym = self.find(returns_str)?;
|
||||
sym.is_type()?;
|
||||
sym.uid.clone()
|
||||
};
|
||||
self.syms.insert(uid.clone(), Symbol {
|
||||
name: func_name.to_string(),
|
||||
uid: uid.clone(),
|
||||
span: Some(span),
|
||||
kind: SymbolKind::Function { params, returns },
|
||||
});
|
||||
self.scope.push(Event::Declared {
|
||||
name: func_name.to_string(),
|
||||
uid: uid.clone(),
|
||||
});
|
||||
Ok(uid)
|
||||
}
|
||||
|
||||
pub fn define_struct(&mut self, uid: &UID, params: Parameters) -> Result<()> {
|
||||
let params = self.type_params(params)?;
|
||||
if let SymbolKind::Struct {
|
||||
params: old_params, ..
|
||||
} = &mut self.get_mut(uid).kind
|
||||
{
|
||||
*old_params = params;
|
||||
} else {
|
||||
unreachable!("Defined non-existent struct")
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
use crate::{BinaryOp, UnaryOp};
|
||||
|
||||
use crate::err::*;
|
||||
use crate::semantic::{Symbol, Type, UID};
|
||||
use crate::semantic::{UID, builtin};
|
||||
|
||||
macro_rules! count {
|
||||
() => (0usize);
|
||||
( $x:tt $($xs:tt)* ) => (1usize + count!($($xs)*));
|
||||
}
|
||||
|
||||
macro_rules! primitives {
|
||||
( $($i:ident),* ) => {
|
||||
|
@ -14,6 +19,8 @@ macro_rules! primitives {
|
|||
}
|
||||
|
||||
impl Primitive {
|
||||
pub const ALL: [Primitive; count!($($i)*,) - 1] = [$(Primitive::$i),*];
|
||||
|
||||
pub fn from_string(string: &str) -> Option<Self> {
|
||||
match string {
|
||||
$(stringify!{$i} => Some(Self::$i),)*
|
||||
|
@ -23,10 +30,10 @@ macro_rules! primitives {
|
|||
|
||||
pub fn mangle(&self) -> UID {
|
||||
match self {
|
||||
Primitive::integer_ambiguous => "$$integer_amgibuous".into(),
|
||||
Primitive::real_ambiguous => "$$real_amgibuous".into(),
|
||||
Primitive::integer_ambiguous => builtin::mangle("integer_ambiguous"),
|
||||
Primitive::real_ambiguous => builtin::mangle("real_ambiguous"),
|
||||
$(
|
||||
Primitive::$i => format!("$${}", stringify!{$i}),
|
||||
Primitive::$i => builtin::mangle(stringify!{$i}),
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue