Reworking semantic analyzer

This commit is contained in:
Logan 2024-10-26 00:58:41 -05:00
parent 7e110a9560
commit 22c78a9945
14 changed files with 552 additions and 430 deletions

View file

@ -1,3 +1,2 @@
10 + 2 + 3 * 4; b := 10.0 / 5.0;
c := b;

View file

@ -4,18 +4,8 @@
</head> </head>
<script> <script>
const importObject = { const url = '/test.wasm';
console: { WebAssembly.instantiateStreaming(fetch(url), { console });
log(arg) {
console.log(arg);
}
}
};
WebAssembly.instantiateStreaming(fetch("/test.wasm"), importObject)
.then(obj => {
obj.instance.exports.main();
});
</script> </script>
<body> <body>

View file

@ -1,9 +1,8 @@
use std::path::Path; use std::{io::Write, path::Path};
use crate::{ use crate::{
Parser, Tokenizer, Parser, Tokenizer,
err::*, err::*,
ir::{Compiler, IR},
semantic::{self}, semantic::{self},
}; };
@ -11,7 +10,6 @@ use crate::{
pub struct Module { pub struct Module {
file_name: String, file_name: String,
source: String, source: String,
pub program: Vec<IR>,
} }
impl Module { impl Module {
@ -31,12 +29,20 @@ impl Module {
let tokens = Tokenizer::new(source.chars()).filter(|t| t.0.is_meaningful()); let tokens = Tokenizer::new(source.chars()).filter(|t| t.0.is_meaningful());
let statements = Parser::new(tokens); let statements = Parser::new(tokens);
let program = semantic::Analyzer::typecheck(statements.collect()); let program = semantic::Analyzer::typecheck(statements.collect());
let mut compiler = Compiler::new();
compiler.compile(program);
Self { Self {
file_name, file_name,
source: source.into(), source: source.into(),
program: compiler.ir,
} }
} }
/*
pub fn write_to(&self, path: impl AsRef<Path>) {
let watpath = path.as_ref().to_owned().with_extension("wat");
let mut file = std::fs::File::create(watpath).unwrap();
file.write_all(&self.wat.as_bytes()).unwrap();
let wasmpath = path.as_ref().to_owned().with_extension("wasm");
let mut file = std::fs::File::create(wasmpath).unwrap();
file.write_all(&self.wasm).unwrap();
}
*/
} }

144
src/ir.rs
View file

@ -1,27 +1,28 @@
use crate::{ use crate::{
BinaryOp, Expression, ExpressionKind, Immediate, Statement, StatementKind, BinaryOp, Expression, ExpressionKind, Immediate, Statement, StatementKind,
UnaryOp, UnaryOp,
semantic::{Type, VarKind, uid}, semantic::{Primitive, Type, UID},
}; };
/*
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum IR { pub enum IR {
BinOp { op: BinaryOp, type_: Type }, BinOp { op: BinaryOp, type_: Type },
UnOp { op: UnaryOp, type_: Type }, UnOp { op: UnaryOp, type_: Type },
Imm(Immediate), Push { prim: Primitive, value: Immediate },
NewLocal { uid: uid, type_: Type }, NewLocal { uid: UID, type_: Type },
AssignLocal { uid: uid }, AssignLocal { uid: UID },
GetLocal { uid: uid }, GetLocal { uid: UID },
NewGlobal { uid: uid, type_: Type }, NewGlobal { uid: UID, type_: Type },
AssignGlobal { uid: uid }, AssignGlobal { uid: UID },
GetGlobal { uid: uid }, GetGlobal { uid: UID },
StartFunc { uid: uid }, StartFunc { uid: UID },
EndFunc, EndFunc,
ReturnType { type_: Type }, ReturnType { type_: Type },
NewParam { uid: uid, type_: Type }, NewParam { uid: UID, type_: Type },
Return, Return,
Call { uid: uid }, Call { uid: UID },
Drop, Drop,
Print,
} }
impl std::fmt::Display for IR { impl std::fmt::Display for IR {
@ -30,7 +31,7 @@ impl std::fmt::Display for IR {
match self { match self {
BinOp { op, type_ } => write!(f, "{op} ({type_})"), BinOp { op, type_ } => write!(f, "{op} ({type_})"),
UnOp { op, type_ } => write!(f, "{op}, {type_}"), UnOp { op, type_ } => write!(f, "{op}, {type_}"),
Imm(immediate) => write!(f, "push {immediate}"), Push { prim, value } => write!(f, "push {value} ({prim})"),
NewLocal { uid, type_ } => write!(f, "local ${uid} = {type_}"), NewLocal { uid, type_ } => write!(f, "local ${uid} = {type_}"),
AssignLocal { uid } => write!(f, "pop local ${uid}"), AssignLocal { uid } => write!(f, "pop local ${uid}"),
GetLocal { uid } => write!(f, "push local ${uid}"), GetLocal { uid } => write!(f, "push local ${uid}"),
@ -44,24 +45,109 @@ impl std::fmt::Display for IR {
Call { uid } => write!(f, "call ${uid}"), Call { uid } => write!(f, "call ${uid}"),
Drop => write!(f, "pop"), Drop => write!(f, "pop"),
ReturnType { type_ } => write!(f, "result {type_}"), ReturnType { type_ } => write!(f, "result {type_}"),
Print => write!(f, "print [DEBUG]"),
} }
} }
} }
impl IR {
pub fn to_wat(&self) -> String {
use BinaryOp as b;
use IR::*;
use Primitive as p;
use Type as t;
match self {
// Primitive
BinOp {
op,
type_: t::Prim(p),
} => match (op, p) {
// Addition
(b::Plus, p::i32 | p::w32 | p::integer | p::whole) => "i32.add",
(b::Plus, p::i64 | p::w64) => "i64.add",
(b::Plus, p::r32) => "f32.add",
(b::Plus, p::r64) => "f64.add",
// Subtraction
(b::Minus, p::i32 | p::w32 | p::integer | p::whole) => "i32.sub",
(b::Minus, p::i64 | p::w64) => "i64.sub",
(b::Minus, p::r32) => "f32.sub",
(b::Minus, p::r64) => "f64.sub",
// Multiplication
(b::Star, p::i32 | p::w32 | p::integer | p::whole) => "i32.mul",
(b::Star, p::i64 | p::w64) => "i64.mul",
(b::Star, p::r32) => "f32.mul",
(b::Star, p::r64) => "f64.mul",
// Division
(b::Slash, p::i32 | p::integer) => "i32.div_s",
(b::Slash, p::w32 | p::whole) => "i32.div_u",
(b::Slash, p::i64) => "i64.div_s",
(b::Slash, p::w64) => "i64.div_u",
(b::Slash, p::r32) => "f32.div",
(b::Slash, p::r64) => "f64.div",
_ => todo!(),
}
.into(),
UnOp {
op,
type_: t::Prim(p),
} => todo!(),
Push { prim, value } => todo!(),
NewLocal {
uid,
type_: t::Prim(p),
} => format!("(local ${uid} {})", p.as_wat()),
AssignLocal { uid } => format!("local.set ${uid}"),
GetLocal { uid } => format!("local.get ${uid}"),
NewGlobal {
uid,
type_: t::Prim(p),
} => format!(
"(global ${uid} (mut {}) ({}.const 0))",
p.as_wat(),
p.as_wat()
),
AssignGlobal { uid } => format!("global.set ${uid}"),
GetGlobal { uid } => format!("global.get ${uid}"),
StartFunc { uid } => format!("(func ${uid}"),
EndFunc => ")".into(),
ReturnType { type_: t::Prim(p) } => format!("(result {})", p.as_wat()),
NewParam {
uid,
type_: t::Prim(p),
} => format!("(param ${uid} {})", p.as_wat()),
Return => "return".into(),
Call { uid } => format!("call ${uid}"),
Drop => "drop".into(),
Print => "call $log".into(),
_ => todo!(),
}
.into()
}
}
pub struct Compiler { pub struct Compiler {
pub ir: Vec<IR>, pub ir: Vec<IR>,
} }
impl Compiler { impl Compiler {
pub fn new() -> Self { const IMPORTS: &'static str =
Self { ir: vec![] } r#"(import "console" "log" (func $log (param i32)))"#;
}
pub fn compile(&mut self, block: Vec<Statement>) { pub fn compile(block: Vec<Statement>) -> (Vec<u8>, String) {
let mut this = Self { ir: vec![] };
for s in block { for s in block {
self.statement(s); this.statement(s);
} }
self.ir = self.hoist_functions(); this.ir = this.hoist();
let mut output = String::new();
for ir in &this.ir {
//println!("{ir}");
let s = ir.to_wat();
output.push_str(&format!("{s}\n"));
}
output = format!("(module\n{}\n{output}\n(start $0)\n)", Self::IMPORTS);
println!("{output}");
(wat::parse_str(&output).unwrap(), output)
} }
fn statement(&mut self, statement: Statement) { fn statement(&mut self, statement: Statement) {
@ -109,7 +195,10 @@ impl Compiler {
else_, else_,
} => todo!(), } => todo!(),
While { predicate, block } => todo!(), While { predicate, block } => todo!(),
Print(expression) => todo!(), Print(expression) => {
self.expression(expression);
self.ir.push(IR::Print);
},
Expression(expression) => { Expression(expression) => {
if expression.type_ == Type::Nothing { if expression.type_ == Type::Nothing {
self.expression(expression); self.expression(expression);
@ -139,7 +228,13 @@ impl Compiler {
use ExpressionKind::*; use ExpressionKind::*;
match expression.kind { match expression.kind {
Immediate(immediate) => { Immediate(immediate) => {
self.ir.push(IR::Imm(immediate)); let Type::Prim(p) = expression.type_ else {
panic!();
};
self.ir.push(IR::Push {
value: immediate,
prim: p,
})
}, },
Identifier(_, var_kind) => match var_kind { Identifier(_, var_kind) => match var_kind {
VarKind::Global(uid) => self.ir.push(IR::GetGlobal { uid }), VarKind::Global(uid) => self.ir.push(IR::GetGlobal { uid }),
@ -152,8 +247,6 @@ impl Compiler {
mut left, mut left,
mut right, mut right,
} => { } => {
left.type_ = Type::coerce(&expression.type_, &left.type_).unwrap();
right.type_ = Type::coerce(&expression.type_, &right.type_).unwrap();
assert!(&left.type_ == &right.type_); assert!(&left.type_ == &right.type_);
self.expression(*left.clone()); self.expression(*left.clone());
self.expression(*right); self.expression(*right);
@ -163,7 +256,6 @@ impl Compiler {
}); });
}, },
Unary { op, mut child } => { Unary { op, mut child } => {
child.type_ = Type::coerce(&expression.type_, &child.type_).unwrap();
self.expression(*child); self.expression(*child);
self.ir.push(IR::UnOp { self.ir.push(IR::UnOp {
op, op,
@ -171,7 +263,6 @@ impl Compiler {
}) })
}, },
Parenthesis(mut e) => { Parenthesis(mut e) => {
e.type_ = Type::coerce(&expression.type_, &e.type_).unwrap();
self.expression(*e); self.expression(*e);
}, },
FunctionDef { FunctionDef {
@ -211,7 +302,7 @@ impl Compiler {
} }
} }
fn hoist_functions(&self) -> Vec<IR> { fn hoist(&self) -> Vec<IR> {
let mut functions = vec![(vec![], vec![])]; let mut functions = vec![(vec![], vec![])];
let mut result = vec![]; let mut result = vec![];
for index in 0..self.ir.len() { for index in 0..self.ir.len() {
@ -259,3 +350,4 @@ impl Compiler {
result result
} }
} }
*/

View file

@ -11,6 +11,7 @@ use std::ops::Add;
use err::*; use err::*;
use lookahead::*; use lookahead::*;
use parse::*; use parse::*;
use semantic::Analyzer;
use token::*; use token::*;
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
@ -85,11 +86,24 @@ fn prints(st: &Statement) {
}; };
} }
fn tokenize(input: &'static str) -> impl Iterator<Item = Token> {
Tokenizer::new(input.chars()).filter(|t| t.0.is_meaningful())
}
fn parse(input: &'static str) -> impl Iterator<Item = Statement> {
Parser::new(tokenize(input))
}
fn typecheck(input: &'static str) -> Vec<Statement> {
Analyzer::typecheck(parse(input).collect())
}
fn main() -> Result<()> { fn main() -> Result<()> {
//test_expression("a.b.c()"); for s in parse(include_str!("../demo.hal")) {
let module = frontend::Module::from_file("./demo.hal")?; println!("{s:#?}");
for s in &module.program { println!("------------------");
println!("{s}");
} }
//let module = frontend::Module::from_file("./demo.hal")?;
//module.write_to("test");
Ok(()) Ok(())
} }

View file

@ -1,4 +1,4 @@
use crate::semantic::*; use crate::{Base, semantic::*};
use super::*; use super::*;
@ -17,8 +17,8 @@ impl std::fmt::Debug for Parameter {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Immediate { pub enum Immediate {
Integer(i64), Integer(String, Base),
Real(f64), Real(String),
String(String), String(String),
Boolean(bool), Boolean(bool),
} }
@ -26,7 +26,7 @@ pub enum Immediate {
impl std::fmt::Display for Immediate { impl std::fmt::Display for Immediate {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Immediate::Integer(i) => write!(f, "{i}"), Immediate::Integer(i, b) => write!(f, "{i} ({b:?})"),
Immediate::Real(r) => write!(f, "{r}"), Immediate::Real(r) => write!(f, "{r}"),
Immediate::String(s) => write!(f, "{s}"), Immediate::String(s) => write!(f, "{s}"),
Immediate::Boolean(b) => write!(f, "{b}"), Immediate::Boolean(b) => write!(f, "{b}"),
@ -37,7 +37,7 @@ impl std::fmt::Display for Immediate {
#[derive(Clone)] #[derive(Clone)]
pub enum ExpressionKind { pub enum ExpressionKind {
Immediate(Immediate), Immediate(Immediate),
Identifier(String, VarKind), Identifier(String, UID),
Binary { Binary {
op: BinaryOp, op: BinaryOp,
left: Box<Expression>, left: Box<Expression>,
@ -53,11 +53,13 @@ pub enum ExpressionKind {
returns_str: Option<String>, returns_str: Option<String>,
returns_actual: Type, returns_actual: Type,
body: Vec<Statement>, body: Vec<Statement>,
id: uid, id: UID,
}, },
FunctionCall { FunctionCall {
callee: Box<Expression>, callee: Box<Expression>,
args: Vec<Expression>, args: Vec<Expression>,
is_reference: bool,
id: UID,
}, },
StructDef(Vec<Parameter>), StructDef(Vec<Parameter>),
StructLiteral { StructLiteral {
@ -67,6 +69,7 @@ pub enum ExpressionKind {
Field { Field {
namespace: Box<Expression>, namespace: Box<Expression>,
field: Box<Expression>, field: Box<Expression>,
uid: UID,
}, },
} }
@ -78,26 +81,16 @@ pub struct Expression {
} }
impl Expression { impl Expression {
pub fn new(kind: ExpressionKind, span: Span) -> Self { pub fn new(kind: ExpressionKind, span: Span, type_: Type) -> Self {
Self { Self { kind, span, type_ }
kind,
span,
type_: Type::Ambiguous,
}
} }
} }
impl std::fmt::Debug for ExpressionKind { impl std::fmt::Debug for ExpressionKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use ExpressionKind as e; use ExpressionKind as e;
use Immediate as im;
match self { match self {
e::Immediate(i) => match i { e::Immediate(i) => write!(f, "{i}"),
im::Integer(i) => write!(f, "{i}"),
im::Real(fp) => write!(f, "{fp}"),
im::String(s) => write!(f, r#""{s}""#),
im::Boolean(b) => write!(f, "{b}"),
},
e::Binary { e::Binary {
op: token, op: token,
left, left,
@ -113,7 +106,9 @@ impl std::fmt::Debug for ExpressionKind {
e::FunctionCall { callee, args, .. } => { e::FunctionCall { callee, args, .. } => {
write!(f, "({callee:?} call {args:?})") write!(f, "({callee:?} call {args:?})")
}, },
e::Field { namespace, field } => { e::Field {
namespace, field, ..
} => {
write!(f, "({namespace:?} . {field:?})") write!(f, "({namespace:?} . {field:?})")
}, },
e::FunctionDef { e::FunctionDef {
@ -131,7 +126,7 @@ impl std::fmt::Debug for ExpressionKind {
impl std::fmt::Debug for Expression { impl std::fmt::Debug for Expression {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.kind) write!(f, "({:?} {})", self.kind, self.type_)
} }
} }
@ -139,6 +134,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
pub fn expression(&mut self, precedence: Precedence) -> Result<Expression> { pub fn expression(&mut self, precedence: Precedence) -> Result<Expression> {
use ExpressionKind as e; use ExpressionKind as e;
use TokenKind as t; use TokenKind as t;
let mut type_ = Type::Ambiguous;
let next = self.peek(0)?; let next = self.peek(0)?;
// Unary prefix expression // Unary prefix expression
let mut current = if let Ok(operator) = UnaryOp::try_from(&next.0) { let mut current = if let Ok(operator) = UnaryOp::try_from(&next.0) {
@ -160,6 +156,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
child: child.into(), child: child.into(),
}, },
span, span,
Type::Ambiguous,
) )
} }
// Terminal or paren // Terminal or paren
@ -191,6 +188,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
right: rhs.into(), right: rhs.into(),
}, },
span, span,
Type::Ambiguous,
); );
} }
// Field // Field
@ -206,8 +204,10 @@ impl<I: Iterator<Item = Token>> Parser<I> {
e::Field { e::Field {
namespace: current.into(), namespace: current.into(),
field: field.into(), field: field.into(),
uid: "".into(),
}, },
span, span,
Type::Ambiguous,
) )
} }
// Function call // Function call
@ -234,8 +234,11 @@ impl<I: Iterator<Item = Token>> Parser<I> {
e::FunctionCall { e::FunctionCall {
callee: current.into(), callee: current.into(),
args, args,
is_reference: false,
id: "".into(),
}, },
span + span2, span + span2,
Type::Ambiguous,
); );
} }
// Unary postfix // Unary postfix
@ -256,6 +259,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
child: current.into(), child: current.into(),
}, },
span, span,
Type::Ambiguous,
); );
} else { } else {
break; break;
@ -268,28 +272,34 @@ impl<I: Iterator<Item = Token>> Parser<I> {
use ExpressionKind as e; use ExpressionKind as e;
use Immediate as im; use Immediate as im;
use TokenKind as t; use TokenKind as t;
let mut type_ = Type::Ambiguous;
let next = self.peek(0)?; let next = self.peek(0)?;
let mut span = next.1; let mut span = next.1;
let kind = match next.0 { let kind = match next.0 {
t::IntegerLiteral(i) => { t::IntegerLiteral(i, b) => {
self.skip(1); self.skip(1);
e::Immediate(im::Integer(i)) type_ = Type::Prim(Primitive::integer_ambiguous);
e::Immediate(im::Integer(i, b))
}, },
t::FloatLiteral(f) => { t::FloatLiteral(f) => {
self.skip(1); self.skip(1);
type_ = Type::Prim(Primitive::real_ambiguous);
e::Immediate(im::Real(f)) e::Immediate(im::Real(f))
}, },
t::StringLiteral(s) => { t::StringLiteral(s) => {
self.skip(1); self.skip(1);
type_ = Type::Prim(Primitive::string);
e::Immediate(im::String(s)) e::Immediate(im::String(s))
}, },
t::True => { t::True => {
self.skip(1); self.skip(1);
type_ = Type::Prim(Primitive::boolean);
e::Immediate(im::Boolean(true)) e::Immediate(im::Boolean(true))
}, },
t::False => { t::False => {
self.skip(1); self.skip(1);
e::Immediate(im::Boolean(true)) type_ = Type::Prim(Primitive::boolean);
e::Immediate(im::Boolean(false))
}, },
// Function definition // Function definition
t::LeftParen t::LeftParen
@ -345,7 +355,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
returns_str, returns_str,
returns_actual: Type::Ambiguous, returns_actual: Type::Ambiguous,
body, body,
id: 0, id: "".into(),
} }
}, },
// Struct definition // Struct definition
@ -405,7 +415,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
}, },
t::Identifier(i) => { t::Identifier(i) => {
self.skip(1); self.skip(1);
e::Identifier(i, VarKind::Undefined) e::Identifier(i, "".into())
}, },
// Parenthetical // Parenthetical
t::LeftParen => { t::LeftParen => {
@ -425,7 +435,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
.reason(format!("Expected expression, found {}", next.0)); .reason(format!("Expected expression, found {}", next.0));
}, },
}; };
Ok(Expression::new(kind, span)) Ok(Expression::new(kind, span, type_))
} }
fn identifier(&mut self) -> Result<(String, Span)> { fn identifier(&mut self) -> Result<(String, Span)> {

View file

@ -1,4 +1,4 @@
use crate::semantic::{Type, VarKind}; use crate::semantic::{Type, UID};
use super::*; use super::*;
@ -10,12 +10,12 @@ pub enum StatementKind {
type_actual: Type, type_actual: Type,
value: Expression, value: Expression,
mutable: bool, mutable: bool,
varkind: VarKind, uid: UID,
}, },
Assignment { Assignment {
name: String, name: String,
value: Expression, value: Expression,
varkind: VarKind, uid: UID,
}, },
If { If {
predicate: Expression, predicate: Expression,
@ -86,7 +86,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
type_actual: Type::Ambiguous, type_actual: Type::Ambiguous,
value, value,
mutable, mutable,
varkind: VarKind::Undefined, uid: "".into(),
}, },
span, span,
}; };
@ -107,7 +107,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
kind: s::Assignment { kind: s::Assignment {
name, name,
value, value,
varkind: VarKind::Undefined, uid: "".into(),
}, },
} }
}, },

View file

@ -1,13 +1,8 @@
use std::any::Any;
use crate::{ use crate::{
BinaryOp, Expression, ExpressionKind, Immediate, Parameter, Statement, Expression, ExpressionKind, Statement, err::*, semantic::SymbolTable,
StatementKind, UnaryOp,
semantic::{Symbol, SymbolTable, Type, VarKind},
}; };
use super::primitives::*; use super::Type;
use crate::err::*;
pub struct Analyzer { pub struct Analyzer {
table: SymbolTable, table: SymbolTable,
@ -15,12 +10,160 @@ pub struct Analyzer {
impl Analyzer { impl Analyzer {
pub fn typecheck(statements: Vec<Statement>) -> Vec<Statement> { pub fn typecheck(statements: Vec<Statement>) -> Vec<Statement> {
/*
let mut this = Self { let mut this = Self {
table: SymbolTable::new(), table: SymbolTable::new(),
}; };
this.block(statements) this.block(statements)
*/
statements
} }
// Bottom up type inference
fn propogate_up(
&mut self,
mut expr: Box<Expression>,
) -> Result<Box<Expression>> {
use ExpressionKind as e;
expr.kind = match expr.kind {
e::Immediate(imm) => e::Immediate(imm),
e::Identifier(id, mut mangle) => {
let symbol = self.table.lookup(&id).span(&expr.span)?;
mangle = symbol.uid;
expr.type_ = symbol.type_;
e::Identifier(id, mangle)
},
e::Binary {
op,
mut left,
mut right,
} => {
left = self.propogate_up(left)?;
right = self.propogate_up(right)?;
expr.type_ =
Type::binary_op(&left.type_, op, &right.type_).span(&expr.span)?;
e::Binary { op, left, right }
},
e::Unary { op, mut child } => {
child = self.propogate_up(child)?;
expr.type_ = Type::unary_op(op, &child.type_).span(&expr.span)?;
e::Unary { op, child }
},
e::Parenthesis(mut inner) => {
inner = self.propogate_up(inner)?;
expr.type_ = inner.type_.clone();
e::Parenthesis(inner)
},
// Define anonymous function, do not evaluate body yet
e::FunctionDef {
mut params,
returns_str,
mut returns_actual,
body,
mut id,
} => {
for p in &mut params {
p.type_actual =
self.table.lookup_typedef(&p.type_str).span(&expr.span)?;
}
let param_types: Vec<_> =
params.iter().map(|p| p.type_actual.clone()).collect();
returns_actual = match returns_str {
Some(ref s) => self.table.lookup_typedef(s).span(&expr.span)?,
None => Type::Nothing,
};
id = self
.table
.start_func(param_types.clone(), returns_actual.clone());
expr.type_ = Type::FunctionDef {
params: param_types,
returns: returns_actual.clone().into(),
id: id.clone(),
};
e::FunctionDef {
params,
returns_str,
returns_actual,
body,
id,
}
},
e::FunctionCall {
mut callee,
mut args,
mut is_reference,
mut id,
} => {
callee = self.propogate_up(callee)?;
let (params, returns) = match callee.type_.clone() {
Type::FunctionRef {
id: uid,
params,
returns,
} => {
is_reference = true;
id = uid;
(params, returns)
},
Type::FunctionDef {
id: uid,
params,
returns,
} => {
is_reference = false;
id = uid;
(params, returns)
},
_ => {
return error()
.reason(format!("Cannot call type '{}'", callee.type_))
.span(&expr.span);
},
};
expr.type_ = *returns;
// Check that args are correct
if args.len() != params.len() {
return error().reason(format!(
"Expected {} arguments, found {}",
params.len(),
args.len()
));
}
for (index, a) in args.iter_mut().enumerate() {
*a = *self.propogate_up(a.clone().into())?;
*a = *self.propogate_down(a.clone().into(), params[index].clone())?;
}
e::FunctionCall {
callee,
args,
is_reference,
id,
}
},
e::StructDef(vec) => todo!(),
e::StructLiteral { ref name, mut args } => {
self.table.lookup_typedef(name).span(&expr.span)?;
todo!()
},
e::Field {
namespace,
field,
uid,
} => todo!(),
};
Ok(expr)
}
// Top down type assertion
fn propogate_down(
&mut self,
expr: Box<Expression>,
expect: Type,
) -> Result<Box<Expression>> {
todo!()
}
/*
fn block(&mut self, block: Vec<Statement>) -> Vec<Statement> { fn block(&mut self, block: Vec<Statement>) -> Vec<Statement> {
let mut new_block = vec![]; let mut new_block = vec![];
for st in block { for st in block {
@ -134,7 +277,9 @@ impl Analyzer {
self.table.end_block(); self.table.end_block();
}, },
s::Print(e) => { s::Print(e) => {
stmt.kind = s::Print(*self.expression(e.into(), None)?); let mut e = *self.expression(e.into(), None)?;
e.type_ = Type::coerce(&Type::Prim(p::integer), &e.type_)?;
stmt.kind = s::Print(e);
}, },
s::Expression(e) => { s::Expression(e) => {
let mut expr = *self.expression(e.into(), None)?; let mut expr = *self.expression(e.into(), None)?;
@ -153,7 +298,8 @@ impl Analyzer {
let return_type = self.table.get_return_type().span(&stmt.span)?; let return_type = self.table.get_return_type().span(&stmt.span)?;
let type_ = match expression { let type_ = match expression {
Some(e) => { Some(e) => {
let e = self.expression(e.into(), Some(return_type.clone()))?; let mut e = self.expression(e.into(), Some(return_type.clone()))?;
e.type_ = Type::coerce(&return_type, &e.type_).span(&e.span)?;
let type_ = e.type_.clone(); let type_ = e.type_.clone();
expression = Some(*e); expression = Some(*e);
type_ type_
@ -178,7 +324,7 @@ impl Analyzer {
use Primitive as p; use Primitive as p;
let type_ = match expr.kind { let type_ = match expr.kind {
e::Immediate(ref i) => Type::Prim(match i { e::Immediate(ref i) => Type::Prim(match i {
i::Integer(_) => p::integer_ambiguous, i::Integer(_, _) => p::integer_ambiguous,
i::Real(_) => p::real_ambiguous, i::Real(_) => p::real_ambiguous,
i::String(_) => p::string, i::String(_) => p::string,
i::Boolean(_) => p::boolean, i::Boolean(_) => p::boolean,
@ -394,4 +540,5 @@ impl Analyzer {
expr.type_ = type_; expr.type_ = type_;
Ok(expr) Ok(expr)
} }
*/
} }

View file

@ -2,201 +2,145 @@ mod analyzer;
mod primitives; mod primitives;
mod types; mod types;
use crate::{Parameter, err::*}; use crate::err::*;
pub use analyzer::*; pub use analyzer::*;
pub use primitives::*; pub use primitives::*;
pub use types::*; pub use types::*;
#[allow(non_camel_case_types)]
pub type uid = u32;
// Variable and function numbering // Mangled name
#[derive(Clone, Copy, Debug)] pub type UID = String;
pub enum VarKind {
Global(uid),
Local(uid),
Function(uid),
Undefined,
}
impl VarKind { #[derive(Debug, Clone)]
pub fn unwrap(self) -> uid {
match self {
VarKind::Global(i) | VarKind::Local(i) | VarKind::Function(i) => i,
VarKind::Undefined => unreachable!("Failed unwrapping uid"),
}
}
}
#[derive(Clone, Debug)]
pub struct Symbol { pub struct Symbol {
pub name: String, name: String,
pub type_: Type, type_: Type,
pub mutable: bool, uid: UID,
pub kind: VarKind,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Definition { enum Definition {
Symbol(Symbol), Ident(Symbol),
FuncStart,
BlockStart, BlockStart,
FuncStart(Type),
}
fn next(array: &mut [uid]) -> uid {
let current = array.last_mut().unwrap();
let ret = *current;
*current += 1;
ret
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct SymbolTable { pub struct SymbolTable {
syms: Vec<Definition>, defs: Vec<Definition>,
mangle_num: usize,
nesting: usize, nesting: usize,
local_varno: Vec<uid>,
global_varno: Vec<uid>,
funcno: uid,
} }
impl SymbolTable { impl SymbolTable {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
syms: vec![], defs: vec![],
mangle_num: 0,
nesting: 0, nesting: 0,
global_varno: vec![0],
local_varno: vec![0],
funcno: 1,
} }
} }
fn define_symbol( fn generate_uid(&mut self, name: &str) -> UID {
&mut self, let uid = format!("${name}${}", self.mangle_num);
name: String, self.mangle_num += 1;
type_: Type, uid
mutable: bool,
) -> Result<VarKind> {
let kind = match type_ {
Type::Prim(_) | Type::Struct(_) | Type::FunctionRef { .. } => {
if self.nesting == 0 {
VarKind::Global(next(&mut self.global_varno))
} else {
VarKind::Local(next(&mut self.local_varno))
}
},
Type::StructDef(_) => {
if mutable {
return error().reason("Struct definition must be immutable");
}
VarKind::Undefined
},
Type::FunctionDef { id, .. } => {
if !mutable {
VarKind::Function(id)
} else {
return error().reason("Function declaration must be immutable");
}
},
_ => VarKind::Undefined,
};
self.syms.push(Definition::Symbol(Symbol {
name,
type_,
mutable,
kind,
}));
Ok(kind)
} }
fn define_param(&mut self, name: String, type_: Type) -> Result<VarKind> { pub fn start_func(&mut self, params: Vec<Type>, returns: Type) -> UID {
let kind = VarKind::Local(next(&mut self.local_varno));
self.syms.push(Definition::Symbol(Symbol {
name,
type_,
mutable: false,
kind,
}));
Ok(kind)
}
fn start_func(&mut self, returns: Type) -> uid {
self.nesting += 1; self.nesting += 1;
self.local_varno.push(0); let uid = self.generate_uid("func");
self.syms.push(Definition::FuncStart(returns)); let type_ = Type::FunctionDef {
let old = self.funcno; params,
self.funcno += 1; returns: returns.into(),
old id: uid.clone(),
};
self.define("<anonymous function>", type_.clone());
self.defs.push(Definition::FuncStart);
uid
} }
fn get_return_type(&mut self) -> Result<Type> { pub fn end_func(&mut self) {
for def in &self.syms { while !self.defs.is_empty() {
if let Definition::FuncStart(t) = def { if let Some(Definition::FuncStart) = self.defs.pop() {
return Ok(t.clone());
}
}
error().reason("Return outside of function")
}
fn end_func(&mut self) {
self.nesting -= 1;
self.local_varno.pop();
while !self.syms.is_empty() {
if let Some(Definition::FuncStart(_)) = self.syms.pop() {
return; return;
} }
} }
unreachable!("Tried to exit global scope in symbol table") unreachable!("Cannot end global scope")
} }
fn start_block(&mut self) { pub fn start_block(&mut self) {
self.syms.push(Definition::BlockStart); while !self.defs.is_empty() {
} if let Some(Definition::BlockStart) = self.defs.pop() {
fn end_block(&mut self) {
while !self.syms.is_empty() {
if let Some(Definition::BlockStart) = self.syms.pop() {
return; return;
} }
} }
unreachable!("Tried to exit global scope in symbol table") unreachable!("Cannot end global scope")
} }
fn find_symbol(&self, find_name: &str) -> Result<Symbol> { pub fn define(&mut self, name: &str, type_: Type) -> UID {
let mut nesting = self.nesting; let uid = self.generate_uid(name);
for s in self.syms.iter().rev() { self.defs.push(Definition::Ident(Symbol {
match s { name: name.to_string(),
Definition::Symbol(sym) type_,
// Only search function local and global scope uid: uid.clone(),
if nesting == self.nesting || nesting == 0 => { }));
// Convert function definition to function reference uid
if find_name == sym.name { }
return Ok(sym.clone());
} pub fn define_func(&mut self, name: &str, uid: UID) {
}, for def in &mut self.defs {
Definition::FuncStart(_) => { match def {
nesting -= 1; Definition::Ident(symbol) if symbol.uid == uid => {
symbol.name = name.to_string();
return;
}, },
_ => {}, _ => {},
}; }
panic!("Tried to name nonexistant function");
} }
error().reason(format!("Symbol '{find_name}' is not defined"))
} }
fn get_type(&self, name: &str) -> Result<Type> { pub fn lookup_typedef(&self, name: &str) -> Result<Type> {
for s in self.syms.iter().rev() { let mut nesting = self.nesting;
if let Definition::Symbol(Symbol { for def in &self.defs {
name: name2, match def {
type_: Type::StructDef(params), Definition::Ident(symbol)
.. if (symbol.name == name)
}) = s && (nesting == 0 || nesting == self.nesting) =>
{ {
if name == name2 { if let Type::StructDef(vec) = &symbol.type_ {
return Ok(Type::Struct(params.clone())); return Ok(Type::Struct(
} vec.iter().map(|p| p.type_actual.clone()).collect(),
));
}
},
Definition::FuncStart => nesting -= 1,
_ => {},
} }
} }
if let Some(p) = Primitive::from_string(name) { if let Some(p) = Primitive::from_string(name) {
return Ok(Type::Prim(p)); return Ok(Type::Prim(p));
} }
error().reason(format!("Type {name} is not defined")) error().reason(format!("Cannot find type definition '{}'", name))
}
pub fn lookup(&self, name: &str) -> Result<Symbol> {
let mut nesting = self.nesting;
for def in &self.defs {
match def {
Definition::Ident(symbol)
if (symbol.name == name)
&& (nesting == 0 || nesting == self.nesting) =>
{
if let Type::StructDef(_) = symbol.type_ {
continue;
}
return Ok(symbol.clone());
},
Definition::FuncStart => nesting -= 1,
_ => {},
}
}
error().reason(format!("Cannot find the definition of '{}'", name))
} }
} }

View file

@ -40,6 +40,22 @@ primitives! {
string, glyph string, glyph
} }
impl Primitive {
pub fn as_wat(&self) -> &'static str {
use Primitive::*;
match self {
boolean | glyph | w8 | w16 | w32 | whole | i8 | i16 | i32 | integer => {
"i32"
},
w64 | i64 => "i64",
r32 | real => "f32",
r64 => "f64",
string => todo!(),
_ => panic!(),
}
}
}
macro_rules! selfsame_basic { macro_rules! selfsame_basic {
( $lhs:ident, $op:ident, $rhs:ident, $binop:ident, $i:ident ) => { ( $lhs:ident, $op:ident, $rhs:ident, $binop:ident, $i:ident ) => {
if ($i == $rhs && $rhs == $lhs) && $op == BinaryOp::$binop { if ($i == $rhs && $rhs == $lhs) && $op == BinaryOp::$binop {
@ -91,47 +107,44 @@ macro_rules! comparison {
} }
impl Primitive { impl Primitive {
pub fn coerce_ambiguous( pub fn coerce(&mut self, into: Primitive) {
lhs: Primitive,
rhs: Primitive,
) -> (Primitive, Primitive) {
use Primitive::*; use Primitive::*;
let is_int = |i| { *self = match (*self, into) {
if let i8 | i16 | i32 | i64 | integer | integer_ambiguous = i { (
true integer_ambiguous,
} else { i8 | i16 | i32 | i64 | integer | w8 | w16 | w32 | w64 | whole,
false ) => into,
} (real_ambiguous, r32 | r64) => into,
_ => *self,
}; };
let is_real = |r| { }
if let r32 | r64 | real | real_ambiguous = r {
true pub fn is_ambiguous(&self) -> bool {
} else { match self {
false Primitive::integer_ambiguous | Primitive::real_ambiguous => true,
} _ => false,
};
// Ambiguous integer coercion
if lhs == integer_ambiguous && is_int(rhs) {
return (rhs, rhs);
} else if rhs == integer_ambiguous && is_int(lhs) {
return (lhs, lhs);
} }
// Ambiguous real coercion }
if lhs == real_ambiguous && is_real(rhs) {
return (rhs, rhs); pub fn promote(&mut self) {
} else if rhs == real_ambiguous && is_real(lhs) { *self = match *self {
return (lhs, lhs); Primitive::integer_ambiguous => Primitive::integer,
Primitive::real_ambiguous => Primitive::real,
_ => *self,
} }
return (lhs, rhs);
} }
pub fn binary_op( pub fn binary_op(
lhs: Primitive, mut lhs: Primitive,
op: BinaryOp, op: BinaryOp,
rhs: Primitive, mut rhs: Primitive,
) -> Result<Primitive> { ) -> Result<Primitive> {
use Primitive::*; use Primitive::*;
let (lhs, rhs) = Primitive::coerce_ambiguous(lhs, rhs); if lhs.is_ambiguous() && !rhs.is_ambiguous() {
lhs.coerce(rhs);
} else if rhs.is_ambiguous() && !lhs.is_ambiguous() {
rhs.coerce(lhs);
}
selfsame_basic! { selfsame_basic! {
lhs, op, rhs; w8, w16, w32, w64, i8, i16, i32, i64, lhs, op, rhs; w8, w16, w32, w64, i8, i16, i32, i64,
integer, integer_ambiguous, real, real_ambiguous integer, integer_ambiguous, real, real_ambiguous
@ -155,7 +168,7 @@ impl Primitive {
error().reason(format!("Unary {} is not defined for {}", op, child)); error().reason(format!("Unary {} is not defined for {}", op, child));
match op { match op {
Minus => match child { Minus => match child {
boolean | string | glyph | w8 | w16 | w32 | w64 => e, boolean | string | glyph | whole | w8 | w16 | w32 | w64 => e,
_ => Ok(child), _ => Ok(child),
}, },
Plus => match child { Plus => match child {

View file

@ -1,10 +1,9 @@
use crate::{ use crate::{
BinaryOp, Expression, ExpressionKind, Immediate, Parameter, Statement, BinaryOp, Expression, ExpressionKind, Immediate, Parameter, Statement,
StatementKind, UnaryOp, StatementKind, UnaryOp,
semantic::{Symbol, SymbolTable},
}; };
use super::{primitives::*, uid}; use super::{UID, primitives::*};
use crate::err::*; use crate::err::*;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -12,16 +11,17 @@ pub enum Type {
Ambiguous, Ambiguous,
Nothing, Nothing,
Prim(Primitive), Prim(Primitive),
Struct(Vec<Parameter>), Struct(Vec<Type>),
StructDef(Vec<Parameter>), StructDef(Vec<Parameter>),
FunctionRef { FunctionRef {
params: Vec<Type>, params: Vec<Type>,
returns: Box<Type>, returns: Box<Type>,
id: UID,
}, },
FunctionDef { FunctionDef {
params: Vec<Type>, params: Vec<Type>,
returns: Box<Type>, returns: Box<Type>,
id: uid, id: UID,
}, },
} }
@ -32,14 +32,14 @@ impl std::fmt::Display for Type {
Type::Nothing => write!(f, "nothing"), Type::Nothing => write!(f, "nothing"),
Type::Prim(primitive) => write!(f, "{primitive}"), Type::Prim(primitive) => write!(f, "{primitive}"),
Type::Struct(vec) => write!(f, "struct {vec:?}"), Type::Struct(vec) => write!(f, "struct {vec:?}"),
Type::StructDef(vec) => write!(f, "struct definition"), Type::StructDef(_) => write!(f, "struct definition"),
Type::FunctionRef { params, returns } => { Type::FunctionRef {
params, returns, ..
} => {
write!(f, "({params:?}) -> {returns}") write!(f, "({params:?}) -> {returns}")
}, },
Type::FunctionDef { Type::FunctionDef {
params, params, returns, ..
returns,
id,
} => write!(f, "({params:?}) -> {returns}"), } => write!(f, "({params:?}) -> {returns}"),
} }
} }
@ -51,20 +51,8 @@ impl PartialEq for Type {
match (self, other) { match (self, other) {
(Ambiguous, Ambiguous) => true, (Ambiguous, Ambiguous) => true,
(Prim(p1), Prim(p2)) if p1 == p2 => true, (Prim(p1), Prim(p2)) if p1 == p2 => true,
(Struct(p1), Struct(p2)) => p1 (Struct(p1), Struct(p2)) => p1.iter().eq(p2.iter()),
.iter() (FunctionRef { id: id1, .. }, FunctionRef { id: id2, .. }) => id1 == id2,
.map(|p| p.type_actual.clone())
.eq(p2.iter().map(|p| p.type_actual.clone())),
(
FunctionRef {
params: p1,
returns: r1,
},
FunctionRef {
params: p2,
returns: r2,
},
) => p1.iter().eq(p2.iter()) && r1 == r2,
(FunctionDef { id: id1, .. }, FunctionDef { id: id2, .. }) => id1 == id2, (FunctionDef { id: id1, .. }, FunctionDef { id: id2, .. }) => id1 == id2,
(Nothing, Nothing) => true, (Nothing, Nothing) => true,
_ => false, _ => false,
@ -97,25 +85,17 @@ impl Type {
} }
} }
pub fn coerce(expect: &Type, actual: &Type) -> Result<Type> { pub fn coerce(&mut self, expect: &Type) {
use Primitive as p;
use Type::*; use Type::*;
let e = || { *self = match (expect, self.clone()) {
error().reason(format!( (Ambiguous, Ambiguous) => Ambiguous,
"Could not coerce type '{actual:?}' into '{expect:?}'" (Ambiguous, t) => t.clone(),
)) (Prim(mut p1), Prim(p2)) => {
}; p1.coerce(p2);
match (expect, actual) { Prim(p1)
(Ambiguous, Ambiguous) => e(),
(Ambiguous, Prim(p::integer_ambiguous)) => Ok(Prim(p::integer)),
(Ambiguous, Prim(p::real_ambiguous)) => Ok(Prim(p::real)),
(Ambiguous, t) => Ok(t.clone()),
(Prim(p1), Prim(p2)) => {
let (p1, p2) = Primitive::coerce_ambiguous(*p1, *p2);
if p1 != p2 { e() } else { Ok(Type::Prim(p1)) }
}, },
(t1, t2) if t1 == t2 => Ok(t1.clone()), (t1, t2) if t1 == &t2 => t1.clone(),
_ => e(), _ => Ambiguous,
} };
} }
} }

View file

@ -1,5 +1,13 @@
use crate::err::*;
use crate::Span; use crate::Span;
use crate::err::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Base {
Binary = 2,
Octal = 8,
Decimal = 10,
Hex = 16,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum TokenKind { pub enum TokenKind {
@ -50,8 +58,8 @@ pub enum TokenKind {
Identifier(String), Identifier(String),
StringLiteral(String), StringLiteral(String),
GlyphLiteral(char), GlyphLiteral(char),
IntegerLiteral(i64), IntegerLiteral(String, Base),
FloatLiteral(f64), FloatLiteral(String),
If, If,
Else, Else,
@ -106,82 +114,7 @@ impl Eq for TokenKind {
impl std::fmt::Display for TokenKind { impl std::fmt::Display for TokenKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use TokenKind::*; write!(f, "{self:?}")
write!(
f,
"'{}'",
match self {
LeftParen => "(",
RightParen => ")",
LeftBrace => "{",
RightBrace => "}",
LeftSquare => "[",
RightSquare => "]",
Comma => ",",
Colon => ":",
Semicolon => ";",
Dot => ".",
DotDot => "..",
Plus => "+",
Minus => "-",
Slash => "/",
Star => "*",
Percent => "%",
Arrow => "->",
FatArrow => "=>",
PlusEqual => "+=",
MinusEqual => "-=",
SlashEqual => "/=",
StarEqual => "*=",
PercentEqual => "%=",
Bang => "!",
BangEqual => "!=",
Question => "?",
QuestionEqual => "?=",
Equal => "=",
DoubleEqual => "==",
Greater => ">",
GreaterEqual => ">=",
Less => "<",
LessEqual => "<=",
Pipe => "|",
Ampersand => "&",
Carrot => "^",
Hash => "#",
DotDotEqual => "..=",
Identifier(i) => i,
StringLiteral(s) => s.as_str(),
GlyphLiteral(_) => "<glyph>",
IntegerLiteral(_) => "<integer>",
FloatLiteral(_) => "<real>",
If => "if",
Else => "else",
And => "and",
Or => "or",
Xor => "xor",
Not => "not",
Nand => "nand",
Nor => "nor",
Xnor => "xnor",
Print => "print",
Break => "break",
Return => "return",
Continue => "continue",
For => "for",
While => "while",
True => "true",
False => "false",
Struct => "struct",
Enum => "enum",
Union => "union",
Whitespace(_) => "<whitespace>",
SmallComment(_) => "<comment>",
BigComment(_) => "<comment>",
Error(_) => "<error>",
Idk => unreachable!(),
EOF => "<end of file>",
}
)
} }
} }
@ -449,7 +382,24 @@ impl<I: Iterator<Item = char>> Tokenizer<I> {
buffer.push(c); buffer.push(c);
let _ = self.next_char(); let _ = self.next_char();
} }
return t(parse_number(&buffer).span(&position)?, position); // Determine base
let base = if buffer.starts_with("0b") {
Base::Binary
} else if buffer.starts_with("0o") || buffer.starts_with("0O") {
Base::Octal
} else if buffer.starts_with("0x") || buffer.starts_with("0X") {
Base::Hex
} else {
Base::Decimal
};
// Determine integer or float
if base == Base::Decimal
&& (encountered_dot || buffer.contains("e") || buffer.contains("E"))
{
return t(FloatLiteral(buffer), position);
} else {
return t(IntegerLiteral(buffer, base), position);
}
} }
// Match keyword or identifier // Match keyword or identifier
while let Some(c) = self.peek(0) { while let Some(c) = self.peek(0) {
@ -504,43 +454,6 @@ impl<I: Iterator<Item = char>> Iterator for Tokenizer<I> {
} }
} }
fn parse_number(num: &str) -> Result<TokenKind> {
use TokenKind::*;
let num = num.replace('_', "");
// Floating point (only decimal)
if num.contains('.') {
num
.parse::<f64>()
.map(|f| FloatLiteral(f))
.reason("Could not parse real number")
}
// Hex integer
else if let Some(hex) = num.strip_prefix("0x") {
i64::from_str_radix(hex, 16)
.map(|i| IntegerLiteral(i))
.reason("Could not parse hex integer number")
}
// Octal integer
else if let Some(oct) = num.strip_prefix("0o") {
i64::from_str_radix(oct, 8)
.map(|i| IntegerLiteral(i))
.reason("Could not parse octal integer number")
}
// Binary integer
else if let Some(bin) = num.strip_prefix("0b") {
i64::from_str_radix(bin, 2)
.map(|i| IntegerLiteral(i))
.reason("Could not parse binary integer number")
}
// Decimal integer
else {
num
.parse::<i64>()
.map(|i| IntegerLiteral(i))
.reason("Could not parse integer number")
}
}
fn bake_string(s: &str) -> Result<String> { fn bake_string(s: &str) -> Result<String> {
let mut baked = String::with_capacity(s.len()); let mut baked = String::with_capacity(s.len());
let mut it = s.chars(); let mut it = s.chars();

BIN
test.wasm

Binary file not shown.

14
test.wat Normal file
View file

@ -0,0 +1,14 @@
(module
(import "console" "log" (func $log (param i32)))
(global $a$0 (mut i32) (i32.const 0))
(func $0
i32.const 10
i32.const 5
i32.div_s
global.set $a$0
global.get $a$0
call $log
)
(start $0)
)