Reworking semantic analyzer
This commit is contained in:
parent
7e110a9560
commit
22c78a9945
14
index.html
14
index.html
|
@ -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>
|
||||||
|
|
|
@ -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
144
src/ir.rs
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
22
src/main.rs
22
src/main.rs
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)> {
|
||||||
|
|
|
@ -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(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
Definition::FuncStart(_) => {
|
pub fn define_func(&mut self, name: &str, uid: UID) {
|
||||||
nesting -= 1;
|
for def in &mut self.defs {
|
||||||
|
match def {
|
||||||
|
Definition::Ident(symbol) if symbol.uid == uid => {
|
||||||
|
symbol.name = name.to_string();
|
||||||
|
return;
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
};
|
|
||||||
}
|
}
|
||||||
error().reason(format!("Symbol '{find_name}' is not defined"))
|
panic!("Tried to name nonexistant function");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
// Ambiguous integer coercion
|
pub fn is_ambiguous(&self) -> bool {
|
||||||
if lhs == integer_ambiguous && is_int(rhs) {
|
match self {
|
||||||
return (rhs, rhs);
|
Primitive::integer_ambiguous | Primitive::real_ambiguous => true,
|
||||||
} else if rhs == integer_ambiguous && is_int(lhs) {
|
_ => false,
|
||||||
return (lhs, lhs);
|
|
||||||
}
|
}
|
||||||
// Ambiguous real coercion
|
|
||||||
if lhs == real_ambiguous && is_real(rhs) {
|
|
||||||
return (rhs, rhs);
|
|
||||||
} else if rhs == real_ambiguous && is_real(lhs) {
|
|
||||||
return (lhs, lhs);
|
|
||||||
}
|
}
|
||||||
return (lhs, rhs);
|
|
||||||
|
pub fn promote(&mut self) {
|
||||||
|
*self = match *self {
|
||||||
|
Primitive::integer_ambiguous => Primitive::integer,
|
||||||
|
Primitive::real_ambiguous => Primitive::real,
|
||||||
|
_ => *self,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
|
|
|
@ -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,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
147
src/token.rs
147
src/token.rs
|
@ -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();
|
||||||
|
|
Loading…
Reference in a new issue