Laptop changes

This commit is contained in:
Logan Gatlin 2024-12-10 21:17:20 -06:00
parent 1ab6bb1e2b
commit c5eed8dcf8
13 changed files with 234 additions and 190 deletions

7
Cargo.lock generated
View file

@ -40,6 +40,7 @@ dependencies = [
name = "lang" name = "lang"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"punycode",
"wat", "wat",
] ]
@ -55,6 +56,12 @@ version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "punycode"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9e1dcb320d6839f6edb64f7a4a59d39b30480d4d1765b56873f7c858538a5fe"
[[package]] [[package]]
name = "unicode-width" name = "unicode-width"
version = "0.1.14" version = "0.1.14"

View file

@ -5,3 +5,4 @@ edition = "2021"
[dependencies] [dependencies]
wat = "1.219" wat = "1.219"
punycode = "0.4"

View file

@ -78,5 +78,7 @@ fn main() -> Result<()> {
*/ */
//let module = frontend::Module::from_file("./demo.hal")?; //let module = frontend::Module::from_file("./demo.hal")?;
//module.write_to("test"); //module.write_to("test");
let p = punycode::encode("-_").unwrap();
println!("{p}");
Ok(()) Ok(())
} }

View file

@ -1,4 +1,4 @@
use crate::{Base, semantic::*}; use crate::Base;
use super::*; use super::*;
@ -45,7 +45,6 @@ pub enum ExpressionKind {
Immediate(Immediate), Immediate(Immediate),
Identifier { Identifier {
name: String, name: String,
uid: UID,
}, },
Binary { Binary {
op: BinaryOp, op: BinaryOp,
@ -60,25 +59,20 @@ pub enum ExpressionKind {
FunctionDef { FunctionDef {
params: Parameters, params: Parameters,
returns_str: Option<String>, returns_str: Option<String>,
returns_actual: Type,
body: Vec<Statement>, body: Vec<Statement>,
uid: UID,
}, },
FunctionCall { FunctionCall {
callee: Box<Expression>, callee: Box<Expression>,
args: Vec<Expression>, args: Vec<Expression>,
uid: UID,
}, },
StructDef(Parameters, UID), StructDef(Parameters),
StructLiteral { StructLiteral {
name: String, name: String,
args: Vec<(String, Expression)>, args: Vec<(String, Expression)>,
uid: UID,
}, },
Field { Field {
namespace: Box<Expression>, namespace: Box<Expression>,
field: Box<Expression>, field: Box<Expression>,
uid: UID,
}, },
Block(Vec<Statement>), Block(Vec<Statement>),
If { If {
@ -92,16 +86,11 @@ pub enum ExpressionKind {
pub struct Expression { pub struct Expression {
pub kind: ExpressionKind, pub kind: ExpressionKind,
pub span: Span, pub span: Span,
pub type_: UID,
} }
impl Expression { impl Expression {
pub fn new(kind: ExpressionKind, span: Span) -> Self { pub fn new(kind: ExpressionKind, span: Span) -> Self {
Self { Self { kind, span }
kind,
span,
type_: "".into(),
}
} }
} }
@ -116,28 +105,28 @@ impl std::fmt::Display for ExpressionKind {
right, right,
} => { } => {
write!(f, "({left} {token} {right})") write!(f, "({left} {token} {right})")
}, }
e::Parenthesis(inner) => write!(f, "{inner}"), e::Parenthesis(inner) => write!(f, "{inner}"),
e::Unary { op: token, child } => { e::Unary { op: token, child } => {
write!(f, "({token} {child})") write!(f, "({token} {child})")
}, }
e::Identifier { name, .. } => write!(f, "{name}"), e::Identifier { name, .. } => write!(f, "{name}"),
e::FunctionCall { callee, args, .. } => { e::FunctionCall { callee, args, .. } => {
write!(f, "({callee} call {args:?})") write!(f, "({callee} call {args:?})")
}, }
e::Field { e::Field {
namespace, field, .. namespace, field, ..
} => { } => {
write!(f, "({namespace} . {field})") write!(f, "({namespace} . {field})")
}, }
e::FunctionDef { e::FunctionDef {
params, params,
returns_actual, returns_str,
.. ..
} => { } => {
write!(f, "(fn({params:?}) -> {returns_actual})") write!(f, "(fn({params:?}) -> {returns_str:?})")
}, }
e::StructDef(params, _) => write!(f, "struct {{ {params:?} }}"), e::StructDef(params) => write!(f, "struct {{ {params:?} }}"),
e::StructLiteral { name, args, .. } => write!(f, "{name} {{ {args:?} }}"), e::StructLiteral { name, args, .. } => write!(f, "{name} {{ {args:?} }}"),
e::Block(block) => { e::Block(block) => {
write!(f, "{{\n")?; write!(f, "{{\n")?;
@ -145,12 +134,8 @@ impl std::fmt::Display for ExpressionKind {
write!(f, "{:#?}", s)?; write!(f, "{:#?}", s)?;
} }
write!(f, "}}") write!(f, "}}")
}, }
e::If { e::If { block, else_, .. } => {
predicate,
block,
else_,
} => {
write!(f, "{{\n")?; write!(f, "{{\n")?;
for s in block { for s in block {
write!(f, "{:#?}", s)?; write!(f, "{:#?}", s)?;
@ -160,14 +145,14 @@ impl std::fmt::Display for ExpressionKind {
write!(f, "{else_}")?; write!(f, "{else_}")?;
} }
Ok(()) Ok(())
}, }
} }
} }
} }
impl std::fmt::Display for Expression { impl std::fmt::Display 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, self.type_) write!(f, "({})", self.kind)
} }
} }
@ -242,7 +227,6 @@ 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,
) )
@ -259,7 +243,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
Ok(a) => { Ok(a) => {
span = span + a.span; span = span + a.span;
args.push(a) args.push(a)
}, }
Err(_) => break, Err(_) => break,
}; };
if !self.eat(t::Comma).is_ok() { if !self.eat(t::Comma).is_ok() {
@ -271,7 +255,6 @@ impl<I: Iterator<Item = Token>> Parser<I> {
e::FunctionCall { e::FunctionCall {
callee: current.into(), callee: current.into(),
args, args,
uid: "".into(),
}, },
span + span2, span + span2,
); );
@ -319,10 +302,9 @@ impl<I: Iterator<Item = Token>> Parser<I> {
names.push(name.clone()); names.push(name.clone());
// Param type (optional) // Param type (optional)
if self.eat(t::Colon).is_ok() { if self.eat(t::Colon).is_ok() {
let (type_name, span2) = self.identifier().trace_span( let (type_name, span2) = self
span + span2, .identifier()
format!("While parsing type of '{}'", name), .trace_span(span + span2, format!("While parsing type of '{}'", name))?;
)?;
strongly_typed = true; strongly_typed = true;
span = span + span2; span = span + span2;
type_names.push(type_name); type_names.push(type_name);
@ -376,38 +358,37 @@ impl<I: Iterator<Item = Token>> Parser<I> {
t::IntegerLiteral(i, b) => { t::IntegerLiteral(i, b) => {
self.skip(1); self.skip(1);
e::Immediate(im::Integer(i, b)) e::Immediate(im::Integer(i, b))
}, }
t::FloatLiteral(f) => { t::FloatLiteral(f) => {
self.skip(1); self.skip(1);
e::Immediate(im::Real(f)) e::Immediate(im::Real(f))
}, }
t::StringLiteral(s) => { t::StringLiteral(s) => {
self.skip(1); self.skip(1);
e::Immediate(im::String(s)) e::Immediate(im::String(s))
}, }
t::GlyphLiteral(c) => { t::GlyphLiteral(c) => {
self.skip(1); self.skip(1);
e::Immediate(im::Glyph(c)) e::Immediate(im::Glyph(c))
}, }
t::True => { t::True => {
self.skip(1); self.skip(1);
e::Immediate(im::Boolean(true)) e::Immediate(im::Boolean(true))
}, }
t::False => { t::False => {
self.skip(1); self.skip(1);
e::Immediate(im::Boolean(false)) e::Immediate(im::Boolean(false))
}, }
t::If => return self.if_else(), t::If => return self.if_else(),
t::LeftBrace => { t::LeftBrace => {
let (block, span1) = self.block()?; let (block, span1) = self.block()?;
span = span + span1; span = span + span1;
e::Block(block) e::Block(block)
}, }
// Function definition // Function definition
t::LeftParen t::LeftParen
if (self.look(1, t::Identifier("".into())).is_ok() if (self.look(1, t::Identifier("".into())).is_ok()
&& (self.look(2, t::Colon).is_ok() && (self.look(2, t::Colon).is_ok() || self.look(2, t::Comma).is_ok()))
|| self.look(2, t::Comma).is_ok()))
|| self.look(1, t::RightParen).is_ok() => || self.look(1, t::RightParen).is_ok() =>
{ {
self.skip(1); self.skip(1);
@ -434,19 +415,17 @@ impl<I: Iterator<Item = Token>> Parser<I> {
e::FunctionDef { e::FunctionDef {
params, params,
returns_str, returns_str,
returns_actual: Type::Ambiguous,
body, body,
uid: "".into(),
} }
}, }
// Struct definition // Struct definition
t::Struct => { t::Struct => {
self.skip(1); self.skip(1);
self.eat(t::LeftBrace)?; self.eat(t::LeftBrace)?;
let params = self.parameters(span)?; let params = self.parameters(span)?;
self.eat(t::RightBrace)?; self.eat(t::RightBrace)?;
e::StructDef(params, "".into()) e::StructDef(params)
}, }
// Struct literal // Struct literal
t::Identifier(name) if self.look(1, t::LeftBrace).is_ok() => { t::Identifier(name) if self.look(1, t::LeftBrace).is_ok() => {
self.skip(2); self.skip(2);
@ -470,19 +449,12 @@ impl<I: Iterator<Item = Token>> Parser<I> {
} }
} }
self.eat(t::RightBrace)?; self.eat(t::RightBrace)?;
e::StructLiteral { e::StructLiteral { name, args }
name,
args,
uid: "".into(),
} }
},
t::Identifier(i) => { t::Identifier(i) => {
self.skip(1); self.skip(1);
e::Identifier { e::Identifier { name: i }
name: i,
uid: "".into(),
} }
},
// Parenthetical // Parenthetical
t::LeftParen => { t::LeftParen => {
self.skip(1); self.skip(1);
@ -494,12 +466,12 @@ impl<I: Iterator<Item = Token>> Parser<I> {
.reason("Unclosed '('") .reason("Unclosed '('")
.span(&expr.span)?; .span(&expr.span)?;
e::Parenthesis(expr.into()) e::Parenthesis(expr.into())
}, }
_ => { _ => {
return error() return error()
.span(&span) .span(&span)
.reason(format!("Expected expression, found {}", next.0)); .reason(format!("Expected expression, found {}", next.0));
}, }
}; };
Ok(Expression::new(kind, span)) Ok(Expression::new(kind, span))
} }
@ -540,7 +512,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
Ok(Token(t::Identifier(i), span)) => { Ok(Token(t::Identifier(i), span)) => {
self.skip(1); self.skip(1);
Ok((i, span)) Ok((i, span))
}, }
Ok(t) => error() Ok(t) => error()
.reason(format!("Expected identifier, found {}", t.0)) .reason(format!("Expected identifier, found {}", t.0))
.span(&t.1), .span(&t.1),

View file

@ -1,5 +1,3 @@
use crate::semantic::UID;
use super::*; use super::*;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -47,7 +45,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
Ok(Token(t::Identifier(s), span2)) => { Ok(Token(t::Identifier(s), span2)) => {
span = span + span2; span = span + span2;
Some(s) Some(s)
}, }
_ => None, _ => None,
}; };
let mutable = if self.eat(t::Equal).is_ok() { let mutable = if self.eat(t::Equal).is_ok() {
@ -63,10 +61,9 @@ impl<I: Iterator<Item = Token>> Parser<I> {
.expression(0) .expression(0)
.trace_span(span, "while parsing declaration")?; .trace_span(span, "while parsing declaration")?;
span = span + value.span; span = span + value.span;
let no_semicolon = let no_semicolon = if let ExpressionKind::FunctionDef { .. } = value.kind {
if let ExpressionKind::FunctionDef { .. } = value.kind {
true true
} else if let ExpressionKind::StructDef(_, _) = value.kind { } else if let ExpressionKind::StructDef(_) = value.kind {
true true
} else { } else {
false false
@ -84,7 +81,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
return Ok(s); return Ok(s);
} }
s s
}, }
// Assignment // Assignment
(Token(t::Identifier(name), span2), Ok(Token(t::Equal, span3))) => { (Token(t::Identifier(name), span2), Ok(Token(t::Equal, span3))) => {
self.skip(2); self.skip(2);
@ -96,7 +93,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
span, span,
kind: s::Assignment { name, value }, kind: s::Assignment { name, value },
} }
}, }
// While // While
(Token(t::While, span2), _) => { (Token(t::While, span2), _) => {
self.skip(1); self.skip(1);
@ -117,7 +114,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
block: block.0, block: block.0,
}, },
}); });
}, }
// (DEBUG) print // (DEBUG) print
(Token(t::Print, span2), _) => { (Token(t::Print, span2), _) => {
self.skip(1); self.skip(1);
@ -130,7 +127,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
span, span,
kind: s::Print(expr), kind: s::Print(expr),
} }
}, }
// Return // Return
(Token(t::Return, span2), _) => { (Token(t::Return, span2), _) => {
span = span + span2; span = span + span2;
@ -143,7 +140,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
span, span,
kind: s::Return(expr), kind: s::Return(expr),
} }
}, }
// Expression // Expression
(Token(_, span2), _) => { (Token(_, span2), _) => {
span = span + span2; span = span + span2;
@ -165,14 +162,14 @@ impl<I: Iterator<Item = Token>> Parser<I> {
span, span,
kind: s::Expression(expr), kind: s::Expression(expr),
}); });
}, }
_ => Statement { _ => Statement {
span, span,
kind: s::Expression(expr), kind: s::Expression(expr),
}, },
} }
} }
}, }
}; };
// Check for semicolon // Check for semicolon
if self.eat(t::Semicolon).is_ok() { if self.eat(t::Semicolon).is_ok() {

View file

@ -1,3 +1,53 @@
use crate::{Expression, ExpressionKind, Statement, StatementKind}; use std::collections::HashMap;
use crate::{err::*, Expression, ExpressionKind, Statement, StatementKind};
use super::*; use super::*;
use ir::*;
#[derive(Debug, Clone)]
enum Undo {
FuncGuard,
BlockGuard,
Symbol { name: String, prev: Vec<Symbol> },
Push { name: String },
None,
}
#[derive(Debug, Clone)]
struct Symbol {
mangle: SID,
type_: TID,
life: Lifetime,
}
#[derive(Debug, Clone)]
struct SymbolTable {
types: HashMap<TID, Type>,
table: HashMap<String, Vec<Symbol>>,
undo_stack: Vec<Undo>,
path: Vec<String>,
salt: usize,
}
impl SymbolTable {
fn define(&mut self, name: &str, type_: TID, life: Lifetime) {
if !self.table.contains_key(name) {
self.table.insert(name.to_string(), vec![]);
}
let symbols = self.table.get_mut(name).unwrap();
let mut path = self.path.clone();
path.push(name.to_string());
let mangle = names::mangle(path, &format!("{:#x}", self.salt));
let symbol = Symbol {
mangle,
type_,
life,
};
let undo = if
}
}
pub fn analyze_block(stmts: Vec<Statement>) -> Result<Vec<IrNode>> {
todo!()
}

View file

@ -1,23 +1,23 @@
use super::{UID, primitives::Primitive}; use super::{primitives::Primitive, SID};
pub fn mangle(input: &str) -> UID { pub fn mangle(input: &str) -> SID {
format!("$${input}") format!("$B${input}")
} }
// Nothing ever happens // Nothing ever happens
pub fn nothing() -> UID { pub fn nothing() -> SID {
mangle("nothing") mangle("nothing")
} }
pub fn integer() -> UID { pub fn integer() -> SID {
Primitive::integer_ambiguous.mangle() Primitive::integer_ambiguous.mangle()
} }
pub fn real() -> UID { pub fn real() -> SID {
Primitive::real_ambiguous.mangle() Primitive::real_ambiguous.mangle()
} }
pub fn all() -> Vec<UID> { pub fn all() -> Vec<SID> {
let mut uids = Primitive::ALL.map(|p| p.mangle()).to_vec(); let mut uids = Primitive::ALL.map(|p| p.mangle()).to_vec();
uids.push(nothing()); uids.push(nothing());
uids uids

53
src/semantic/ir.rs Normal file
View file

@ -0,0 +1,53 @@
use crate::{BinaryOp, UnaryOp};
use super::{Type, SID, TID};
#[derive(Clone, Debug)]
pub struct IrBlock {
nodes: Vec<IrNode>,
}
#[derive(Clone, Debug)]
pub enum IrNode {
Declaration {
uid: SID,
mutable: bool,
size: usize,
value: IrExpr,
},
Function {
uid: SID,
parameters: Vec<Type>,
block: IrBlock,
},
Conditional {
branches: Vec<(IrExpr, IrBlock)>,
default: IrBlock,
},
Expr(IrExpr),
}
#[derive(Clone, Debug)]
pub struct IrExpr {
kind: IrExprKind,
type_: TID,
}
#[derive(Clone, Debug)]
pub enum IrExprKind {
Ident(SID),
UnOp {
op: UnaryOp,
child: Box<IrExpr>,
},
BinOp {
op: BinaryOp,
left: Box<IrExpr>,
right: Box<IrExpr>,
},
Block(IrBlock),
Call {
function: SID,
args: Vec<IrExpr>,
},
}

View file

@ -1,12 +1,25 @@
pub mod analyzer; pub mod analyzer;
mod builtin; pub mod builtin;
pub mod ir;
pub mod names;
pub mod primitives; pub mod primitives;
pub use primitives::*; pub use primitives::*;
use crate::{BinaryOp, UnaryOp, semantic::Primitive}; use crate::semantic::Primitive;
pub type UID = String; /// Type ID
pub type TID = usize;
/// Name mangle
pub type SID = String;
#[derive(Debug, Clone, Copy)]
pub enum Lifetime {
/// Exists for lifetime of program
Static,
/// Exists for lifetime of contained scope
Dynamic,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Type { pub enum Type {
@ -14,8 +27,18 @@ pub enum Type {
Prim(Primitive), Prim(Primitive),
Nothing, Nothing,
Never, Never,
Struct(UID), Struct {
Function(UID), size: usize,
name: String,
member_names: Vec<String>,
member_types: Vec<TID>,
},
Alias(TID),
Function {
name: String,
arg_names: Vec<String>,
arg_types: Vec<TID>,
},
} }
impl std::fmt::Display for Type { impl std::fmt::Display for Type {
@ -24,52 +47,10 @@ impl std::fmt::Display for Type {
Type::Ambiguous => write!(f, "ambiguous"), Type::Ambiguous => write!(f, "ambiguous"),
Type::Prim(primitive) => write!(f, "{primitive}"), Type::Prim(primitive) => write!(f, "{primitive}"),
Type::Nothing => write!(f, "nothing"), Type::Nothing => write!(f, "nothing"),
Type::Struct(s) => write!(f, "struct {s}"),
Type::Function(func) => write!(f, "func {func}"),
Type::Never => write!(f, "never"), Type::Never => write!(f, "never"),
Type::Struct { name, .. } => write!(f, "struct {name}"),
Type::Alias(tid) => write!(f, "alias ({tid})"),
Type::Function { name, .. } => write!(f, "func ({name})"),
} }
} }
} }
#[derive(Clone, Debug)]
pub struct IrBlock {
nodes: Vec<IrNode>,
}
#[derive(Clone, Debug)]
pub enum IrNode {
Declaration {
uid: UID,
mutable: bool,
size: usize,
value: IrExpr,
},
Function {
uid: UID,
parameters: Vec<Type>,
block: IrBlock,
},
Conditional {
branches: Vec<(IrExpr, IrBlock)>,
default: IrBlock,
},
Expr(IrExpr),
}
#[derive(Clone, Debug)]
pub enum IrExpr {
Ident(UID),
UnOp {
op: UnaryOp,
child: Box<IrExpr>,
},
BinOp {
op: BinaryOp,
left: Box<IrExpr>,
right: Box<IrExpr>,
},
Call {
function: UID,
args: Vec<IrExpr>,
},
}

16
src/semantic/names.rs Normal file
View file

@ -0,0 +1,16 @@
// <mangle> ::= "$" <path> <salt>
// <path> ::= {<path-element>}*
// <path-element> ::= <length> <ident>
// <ident> ::= <_a-zA-Z> {<_a-zA-Z0-9>}*
// <length> ::= {<0-9>}+
// <salt> ::= {<a-zA-Z>}*
pub fn mangle(path: Vec<String>, salt: &str) -> String {
let mut buf: Vec<u8> = vec![];
for p in path {
let bytes = format!("{}{}", p.len(), punycode::encode(&p).unwrap());
buf.extend_from_slice(bytes.as_bytes());
}
buf.extend_from_slice(salt.as_bytes());
String::from_utf8(buf).unwrap()
}

View file

@ -1,7 +1,7 @@
use crate::{BinaryOp, UnaryOp}; use crate::{BinaryOp, UnaryOp};
use crate::err::*; use crate::err::*;
use crate::semantic::{UID, builtin}; use crate::semantic::{builtin, SID};
macro_rules! count { macro_rules! count {
() => (0usize); () => (0usize);
@ -28,7 +28,7 @@ macro_rules! primitives {
} }
} }
pub fn mangle(&self) -> UID { pub fn mangle(&self) -> SID {
match self { match self {
Primitive::integer_ambiguous => builtin::mangle("integer_ambiguous"), Primitive::integer_ambiguous => builtin::mangle("integer_ambiguous"),
Primitive::real_ambiguous => builtin::mangle("real_ambiguous"), Primitive::real_ambiguous => builtin::mangle("real_ambiguous"),
@ -62,9 +62,7 @@ impl Primitive {
pub fn as_wat(&self) -> &'static str { pub fn as_wat(&self) -> &'static str {
use Primitive::*; use Primitive::*;
match self { match self {
boolean | glyph | w8 | w16 | w32 | whole | i8 | i16 | i32 | integer => { boolean | glyph | w8 | w16 | w32 | whole | i8 | i16 | i32 | integer => "i32",
"i32"
},
w64 | i64 => "i64", w64 | i64 => "i64",
r32 | real => "f32", r32 | real => "f32",
r64 => "f64", r64 => "f64",
@ -128,16 +126,11 @@ impl Primitive {
pub fn coerce(self, expect: Primitive) -> Result<Self> { pub fn coerce(self, expect: Primitive) -> Result<Self> {
use Primitive::*; use Primitive::*;
match (self, expect) { match (self, expect) {
( (integer_ambiguous, a @ (i8 | i16 | i32 | i64 | integer | w8 | w16 | w32 | w64 | whole))
integer_ambiguous, | (a @ (i8 | i16 | i32 | i64 | integer | w8 | w16 | w32 | w64 | whole), integer_ambiguous) => {
a @ (i8 | i16 | i32 | i64 | integer | w8 | w16 | w32 | w64 | whole), Ok(a)
) }
| ( (real_ambiguous, a @ (r32 | r64 | real)) | (a @ (r32 | r64 | real), real_ambiguous) => Ok(a),
a @ (i8 | i16 | i32 | i64 | integer | w8 | w16 | w32 | w64 | whole),
integer_ambiguous,
) => Ok(a),
(real_ambiguous, a @ (r32 | r64 | real))
| (a @ (r32 | r64 | real), real_ambiguous) => Ok(a),
(t1, t2) if t1 == t2 => Ok(t1), (t1, t2) if t1 == t2 => Ok(t1),
_ => error().reason(format!("Cannot coerce '{self}' into '{expect}'")), _ => error().reason(format!("Cannot coerce '{self}' into '{expect}'")),
} }
@ -158,11 +151,7 @@ impl Primitive {
} }
} }
pub fn binary_op( pub fn binary_op(mut lhs: Primitive, op: BinaryOp, mut rhs: Primitive) -> Result<Primitive> {
mut lhs: Primitive,
op: BinaryOp,
mut rhs: Primitive,
) -> Result<Primitive> {
use Primitive::*; use Primitive::*;
if lhs.is_ambiguous() && !rhs.is_ambiguous() { if lhs.is_ambiguous() && !rhs.is_ambiguous() {
lhs = lhs.coerce(rhs)?; lhs = lhs.coerce(rhs)?;
@ -188,8 +177,7 @@ impl Primitive {
pub fn unary_op(op: UnaryOp, child: Primitive) -> Result<Primitive> { pub fn unary_op(op: UnaryOp, child: Primitive) -> Result<Primitive> {
use Primitive::*; use Primitive::*;
use UnaryOp::*; use UnaryOp::*;
let e = let e = 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 | whole | w8 | w16 | w32 | w64 => e, boolean | string | glyph | whole | w8 | w16 | w32 | w64 => e,

BIN
test.wasm

Binary file not shown.

View file

@ -1,32 +1,9 @@
(module (module
(func $3$func (global $2$s$0 (mut i32) (i32.const 0))
(param $4$s$0 i32) (global $2$s$1 (mut i32) (i32.const 0))
(param $4$s$1 i32) (global $2$s$2 (mut f32) (f32.const 0))
(param $4$s$2 f32)
(param $5$a$0 i32)
(result i32 i32 f32 )
local.get $4$s$2
local.get $4$s$1
local.get $4$s$0
return
)
(global $2$s$0 (mut i32))
(global $2$s$1 (mut i32))
(global $2$s$2 (mut f32))
(func $$main (func $$main
(local $$tmp0$0 i32) (local $$tmp0$0 i32)
(local $$tmp1$0 i32) (local $$tmp1$0 i32)
i32.const 2
i32.const 1
local.set $$tmp0$0
i32.const 97
local.set $$tmp1$0
f32.const 1
local.get $$tmp1$0
local.get $$tmp0$0
call $3$func
global.set $2$s$0
global.set $2$s$1
global.set $2$s$2
) )
) )