More stuff compiles
This commit is contained in:
Generated
+5
@@ -111,6 +111,7 @@ dependencies = [
|
||||
"bitflags",
|
||||
"boxcar",
|
||||
"derive_more",
|
||||
"fxhash",
|
||||
"half",
|
||||
"leaf_allocators",
|
||||
"scc",
|
||||
@@ -121,6 +122,8 @@ name = "leaf_compiler"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"arcstr",
|
||||
"derive_more",
|
||||
"fxhash",
|
||||
"leaf_allocators",
|
||||
"leaf_assembly",
|
||||
"leaf_parser",
|
||||
@@ -133,6 +136,8 @@ dependencies = [
|
||||
"fxhash",
|
||||
"leaf_allocators",
|
||||
"leaf_assembly",
|
||||
"leaf_compiler",
|
||||
"leaf_parser",
|
||||
"scc",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
@@ -37,10 +37,24 @@ impl<'l> dyn Allocator + 'l {
|
||||
&mut *(self.alloc_unsafe(data, layout, drop) as *mut T)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alloc_str(&'l self, str: &str) -> &'l str {
|
||||
unsafe {
|
||||
let ptr =
|
||||
self.alloc_unsafe(str.as_ptr(), Layout::array::<u8>(str.len()).unwrap(), None);
|
||||
let slice = std::slice::from_raw_parts_mut(ptr, str.len());
|
||||
slice.copy_from_slice(str.as_bytes());
|
||||
std::str::from_utf8_unchecked(slice)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'l> dyn SyncAllocator + 'l {
|
||||
pub fn alloc<T: Send>(&'l self, value: T) -> &'l mut T {
|
||||
<dyn Allocator>::alloc(self, value)
|
||||
}
|
||||
|
||||
pub fn alloc_str(&'l self, value: &str) -> &'l str {
|
||||
<dyn Allocator>::alloc_str(self, value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,3 +11,4 @@ half = "2.7.1"
|
||||
scc = "3.3.7"
|
||||
|
||||
leaf_allocators = { path = "../allocators" }
|
||||
fxhash = "0.2.1"
|
||||
|
||||
+29
-12
@@ -1,11 +1,12 @@
|
||||
use crate::{
|
||||
functions::Function,
|
||||
types::derivations::{FuncT, TypeDerivations},
|
||||
values::AnyConst,
|
||||
values::Const,
|
||||
};
|
||||
use derive_more::Debug;
|
||||
use fxhash::FxBuildHasher;
|
||||
use leaf_allocators::SyncAllocator;
|
||||
use scc::{HashMap, HashSet};
|
||||
use scc::HashMap;
|
||||
use std::{borrow::Cow, hash::Hash, sync::OnceLock};
|
||||
|
||||
#[derive(derive_more::Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
@@ -28,6 +29,7 @@ pub type Ctx<'l> = &'l Context<'l>;
|
||||
pub struct Context<'l> {
|
||||
pub(crate) alloc: &'l dyn SyncAllocator,
|
||||
pub(crate) derivations: TypeDerivations<'l>,
|
||||
strings: HashMap<&'l str, &'l str, FxBuildHasher>,
|
||||
assemblies: HashMap<AssemblyIdentifier, &'l Assembly<'l>>,
|
||||
}
|
||||
|
||||
@@ -49,6 +51,7 @@ impl<'l> Context<'l> {
|
||||
pub fn new(alloc: &'l dyn SyncAllocator) -> &'l Self {
|
||||
alloc.alloc(Self {
|
||||
alloc,
|
||||
strings: HashMap::default(),
|
||||
derivations: TypeDerivations::new(alloc),
|
||||
assemblies: Default::default(),
|
||||
})
|
||||
@@ -64,6 +67,15 @@ impl<'l> Context<'l> {
|
||||
.entry_sync(ident.clone())
|
||||
.or_insert_with(|| Assembly::new(self, ident))
|
||||
}
|
||||
|
||||
pub fn intern_str(&'l self, str: &str) -> &'l str {
|
||||
if let Some(value) = self.strings.get_sync(str) {
|
||||
return (*value).into();
|
||||
}
|
||||
let str = self.alloc.alloc_str(str);
|
||||
let _ = self.strings.insert_sync(str, str);
|
||||
str
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -71,12 +83,7 @@ pub struct Assembly<'l> {
|
||||
#[debug(skip)]
|
||||
ctx: &'l Context<'l>,
|
||||
ident: AssemblyIdentifier,
|
||||
#[debug("{:#?}", {
|
||||
let mut c = vec![];
|
||||
constants.iter_sync(|k| {c.push(*k); true});
|
||||
c
|
||||
})]
|
||||
constants: HashSet<AnyConst<'l>>,
|
||||
functions: boxcar::Vec<&'l Function<'l>>,
|
||||
}
|
||||
|
||||
impl Eq for Assembly<'_> {}
|
||||
@@ -98,7 +105,7 @@ impl<'l> Assembly<'l> {
|
||||
let assembly = ctx.alloc.alloc(Self {
|
||||
ctx,
|
||||
ident,
|
||||
constants: HashSet::new(),
|
||||
functions: boxcar::vec![],
|
||||
});
|
||||
assembly
|
||||
}
|
||||
@@ -114,9 +121,19 @@ impl<'l> Assembly<'l> {
|
||||
body: OnceLock::new(),
|
||||
declaring_assembly: self,
|
||||
});
|
||||
self.constants
|
||||
.insert_sync(AnyConst::Function(func))
|
||||
.unwrap();
|
||||
self.functions.push(func);
|
||||
func
|
||||
}
|
||||
|
||||
pub fn find_function(
|
||||
&'l self,
|
||||
filter: impl Fn(&'l Function<'l>) -> bool,
|
||||
) -> Option<&'l Function<'l>> {
|
||||
for (_, func) in self.functions.iter() {
|
||||
if filter(func) {
|
||||
return Some(func);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,8 @@ impl<'l> Instruction<'l> {
|
||||
|
||||
pub fn value_flags(&self) -> ValueFlags {
|
||||
match self.variant {
|
||||
_ => todo!(),
|
||||
InstructionVariant::StackAlloc(_) => ValueFlags::LValue,
|
||||
_ => ValueFlags::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,8 +74,11 @@ impl<'l> Instruction<'l> {
|
||||
_ => unreachable!(),
|
||||
},
|
||||
InstructionVariant::IAdd(a, _) => a.ty(),
|
||||
InstructionVariant::IMul(a, _) => a.ty(),
|
||||
InstructionVariant::FAdd(a, _) => a.ty(),
|
||||
InstructionVariant::FMul(a, _) => a.ty(),
|
||||
InstructionVariant::ICmp(_, _, _) => Type::Bool,
|
||||
InstructionVariant::Call(f, _) => f.ty.ret_t,
|
||||
_ => todo!("{self:?}"),
|
||||
}
|
||||
}
|
||||
@@ -98,7 +102,9 @@ pub enum InstructionVariant<'l> {
|
||||
Store(Value<'l>, Value<'l>),
|
||||
|
||||
IAdd(Value<'l>, Value<'l>),
|
||||
IMul(Value<'l>, Value<'l>),
|
||||
FAdd(Value<'l>, Value<'l>),
|
||||
FMul(Value<'l>, Value<'l>),
|
||||
|
||||
ICmp(Value<'l>, Value<'l>, Cmp),
|
||||
FCmp(Value<'l>, Value<'l>, Cmp),
|
||||
@@ -132,11 +138,17 @@ impl std::fmt::Debug for InstructionVariant<'_> {
|
||||
Self::Load(v) => write!(f, "load {v}"),
|
||||
Self::Store(t, v) => write!(f, "store {t}, {v}"),
|
||||
Self::IAdd(a, b) => write!(f, "iadd {a}, {b}"),
|
||||
Self::IMul(a, b) => write!(f, "imul {a}, {b}"),
|
||||
Self::FAdd(a, b) => write!(f, "fadd {a}, {b}"),
|
||||
Self::FMul(a, b) => write!(f, "fmul {a}, {b}"),
|
||||
Self::ICmp(a, b, c) => write!(f, "icmp {c:?} {a}, {b}"),
|
||||
Self::FCmp(a, b, c) => write!(f, "fcmp {c:?} {a}, {b}"),
|
||||
Self::Call(func, args) => {
|
||||
write!(f, "call {:#?}(", *func as *const Function)?;
|
||||
write!(
|
||||
f,
|
||||
"call {}(",
|
||||
func.name.get().unwrap_or(&"<anonymous function>".into())
|
||||
)?;
|
||||
let mut separator = "";
|
||||
for arg in args {
|
||||
write!(f, "{separator}{arg}")?;
|
||||
@@ -252,6 +264,22 @@ impl<'l> BlockBuilder<'l> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mul(&mut self, a: Value<'l>, b: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> {
|
||||
let [a_ty, b_ty] = [a.ty(), b.ty()];
|
||||
|
||||
match (a_ty, b_ty) {
|
||||
(Type::Int(a_ty), Type::Int(b_ty)) if a_ty == b_ty => {
|
||||
let inst = self.push_instruction(InstructionVariant::IMul(a, b))?;
|
||||
Ok(inst.into())
|
||||
}
|
||||
(Type::Float(a_ty), Type::Float(b_ty)) if a_ty == b_ty => {
|
||||
let inst = self.push_instruction(InstructionVariant::FMul(a, b))?;
|
||||
Ok(inst.into())
|
||||
}
|
||||
_ => Err(format!("Cannot add values of type `{a_ty}` and `b_ty`.").into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cmp(
|
||||
&mut self,
|
||||
a: Value<'l>,
|
||||
@@ -358,7 +386,7 @@ impl<'l> BlockBuilder<'l> {
|
||||
|
||||
pub fn build(self) -> BlockBuilderResult<'l, &'l Block<'l>> {
|
||||
if !self.has_termination() {
|
||||
return Err(format!("Block #{} has not termination.", self.block.id).into());
|
||||
return Err(format!("Block #{} has no termination.", self.block.id).into());
|
||||
}
|
||||
self.block.instructions.set(self.instructions).unwrap();
|
||||
Ok(self.block)
|
||||
@@ -398,15 +426,15 @@ impl<'l> FunctionBodyBuilder<'l> {
|
||||
builder
|
||||
}
|
||||
|
||||
pub fn current_block(&self) -> &'l Block<'l> {
|
||||
self.blocks[self.current_block].block
|
||||
pub fn current_block(&self) -> &BlockBuilder<'l> {
|
||||
&self.blocks[self.current_block]
|
||||
}
|
||||
|
||||
pub fn set_current_block(&mut self, block: &'l Block<'l>) -> Option<&'l Block<'l>> {
|
||||
match std::ptr::eq(block.func, self.func) {
|
||||
false => None,
|
||||
true => {
|
||||
let current = self.current_block();
|
||||
let current = &self.blocks[self.current_block].block;
|
||||
self.current_block = block.id as usize;
|
||||
Some(current)
|
||||
}
|
||||
@@ -466,6 +494,10 @@ impl<'l> FunctionBodyBuilder<'l> {
|
||||
self.current_builder().add(a, b)
|
||||
}
|
||||
|
||||
pub fn mul(&mut self, a: Value<'l>, b: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> {
|
||||
self.current_builder().mul(a, b)
|
||||
}
|
||||
|
||||
pub fn cmp(
|
||||
&mut self,
|
||||
a: Value<'l>,
|
||||
|
||||
@@ -62,6 +62,7 @@ impl FmtDebug for Function<'_> {
|
||||
|
||||
f.debug_struct("Function")
|
||||
.field("ty", &format_args!("{}", self.ty))
|
||||
.field("name", &self.name.get())
|
||||
.field("body", body)
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{functions::Function, types::Type};
|
||||
use crate::{functions::Function, types::Type, values::ValueFlags};
|
||||
use derive_more::{Debug, *};
|
||||
use half::f16;
|
||||
use std::hash::Hash;
|
||||
@@ -9,13 +9,17 @@ pub enum Int {
|
||||
I16(i16),
|
||||
I32(i32),
|
||||
I64(i64),
|
||||
#[from]
|
||||
I128(i128),
|
||||
ISize(i128),
|
||||
|
||||
U8(u8),
|
||||
U16(u16),
|
||||
U32(u32),
|
||||
U64(u64),
|
||||
#[from]
|
||||
U128(u128),
|
||||
USize(u128),
|
||||
}
|
||||
|
||||
#[derive(Debug, Display, Clone, Copy, From, TryInto, PartialEq)]
|
||||
@@ -90,15 +94,25 @@ impl<'l> AnyConst<'l> {
|
||||
Self::Int(Int::I32(_)) => Type::I32,
|
||||
Self::Int(Int::I64(_)) => Type::I64,
|
||||
Self::Int(Int::I128(_)) => Type::I128,
|
||||
Self::Int(Int::ISize(_)) => Type::ISIZE,
|
||||
Self::Int(Int::U8(_)) => Type::U8,
|
||||
Self::Int(Int::U16(_)) => Type::U16,
|
||||
Self::Int(Int::U32(_)) => Type::U32,
|
||||
Self::Int(Int::U64(_)) => Type::U64,
|
||||
Self::Int(Int::U128(_)) => Type::U128,
|
||||
Self::Int(Int::USize(_)) => Type::USIZE,
|
||||
Self::Float(Float::F16(_)) => Type::F16,
|
||||
Self::Float(Float::F32(_)) => Type::F32,
|
||||
Self::Float(Float::F64(_)) => Type::F64,
|
||||
_ => todo!("{self:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flags(&self) -> super::ValueFlags {
|
||||
match self {
|
||||
AnyConst::Function(function) => ValueFlags::Function,
|
||||
AnyConst::Type(_) => ValueFlags::Type,
|
||||
_ => ValueFlags::Const,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use crate::{functions::ir::Instruction, types::Type};
|
||||
use crate::{
|
||||
functions::{Function, ir::Instruction},
|
||||
types::Type,
|
||||
};
|
||||
use bitflags::bitflags;
|
||||
use derive_more::{Debug, Display, *};
|
||||
use std::hash::Hash;
|
||||
@@ -11,6 +14,7 @@ bitflags! {
|
||||
pub struct ValueFlags: u16 {
|
||||
const Mutable = 0b00000000_00000001;
|
||||
const Volatile = 0b00000000_00000010;
|
||||
const LValue = 0b00000000_00000100;
|
||||
const Const = 0b00000001_00000000;
|
||||
const ConstOnly = 0b00000011_00000000;
|
||||
const Type = 0b00000111_00000000;
|
||||
@@ -20,10 +24,15 @@ bitflags! {
|
||||
|
||||
#[derive(Debug, Display, Clone, Copy, From, TryInto, PartialEq, Eq, Hash)]
|
||||
pub enum Value<'l> {
|
||||
Uninit,
|
||||
#[display("{_0}")]
|
||||
Constant(AnyConst<'l>),
|
||||
#[display("{_0}")]
|
||||
Instruction(&'l Instruction<'l>),
|
||||
|
||||
#[debug("${_0}")]
|
||||
#[display("${_0}")]
|
||||
Parameter(usize, &'l Function<'l>),
|
||||
}
|
||||
|
||||
impl From<Int> for Value<'_> {
|
||||
@@ -37,6 +46,17 @@ impl<'l> Value<'l> {
|
||||
match self {
|
||||
Value::Constant(v) => v.ty(),
|
||||
Value::Instruction(v) => v.value_ty(),
|
||||
Value::Parameter(i, f) => f.ty.par_t[*i],
|
||||
Value::Uninit => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flags(&self) -> ValueFlags {
|
||||
match self {
|
||||
Value::Instruction(instruction) => instruction.value_flags(),
|
||||
Value::Parameter(_, _) => ValueFlags::empty(),
|
||||
Value::Constant(c) => c.flags(),
|
||||
_ => todo!("{self:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,3 +8,5 @@ leaf_parser = { path = "../parser" }
|
||||
leaf_assembly = { path = "../assembly" }
|
||||
leaf_allocators = { path = "../allocators" }
|
||||
arcstr = "1.2.0"
|
||||
derive_more = { version = "2.0.1", features = ["deref", "deref_mut", "debug", "display", "try_from", "from", "try_into", "into"] }
|
||||
fxhash = "0.2.1"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use derive_more::Debug;
|
||||
use leaf_parser::{LineCol, ParseError};
|
||||
use std::ops::Range;
|
||||
|
||||
@@ -8,10 +9,14 @@ pub enum Kind {
|
||||
Unknown = 0x0000,
|
||||
|
||||
Parsing = 0x0100,
|
||||
InvalidInteger = 0x0101,
|
||||
|
||||
SymbolNotFound = 0x0200,
|
||||
UninitializedSymbol = 0x0201,
|
||||
NotAType = 0x0202,
|
||||
NotAFunction = 0x0205,
|
||||
InvalidIntegerType = 0x0203,
|
||||
InvalidType = 0x0204,
|
||||
|
||||
FunctionCompilationFailed = 0x0301,
|
||||
}
|
||||
@@ -20,10 +25,12 @@ pub enum Kind {
|
||||
pub enum Location {
|
||||
None,
|
||||
Range {
|
||||
#[debug("{:?}", file.file)]
|
||||
file: SourceFile,
|
||||
range: Range<usize>,
|
||||
},
|
||||
Position {
|
||||
#[debug("{:?}", file.file)]
|
||||
file: SourceFile,
|
||||
position: LineCol,
|
||||
},
|
||||
|
||||
+11
-2
@@ -3,11 +3,11 @@ use arcstr::literal_substr;
|
||||
use leaf_allocators::SyncAllocator;
|
||||
use leaf_assembly::{
|
||||
assembly::{Assembly, AssemblyIdentifier, Context},
|
||||
types::{FloatT, IntT, Type},
|
||||
types::Type,
|
||||
values::{AnyConst, Value},
|
||||
};
|
||||
use leaf_parser::SourceCode;
|
||||
use std::{collections::HashMap, sync::Arc, u32};
|
||||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
mod error;
|
||||
mod scope;
|
||||
@@ -19,6 +19,14 @@ pub struct CompilationContext<'l> {
|
||||
alloc: &'l dyn SyncAllocator,
|
||||
}
|
||||
|
||||
impl<'l> Deref for CompilationContext<'l> {
|
||||
type Target = Context<'l>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.ctx
|
||||
}
|
||||
}
|
||||
|
||||
impl<'l> CompilationContext<'l> {
|
||||
pub fn new(alloc: &'l dyn SyncAllocator) -> Self {
|
||||
Self {
|
||||
@@ -56,6 +64,7 @@ impl<'l> CompilationContext<'l> {
|
||||
scope.insert(
|
||||
literal_substr!($id),
|
||||
Value::Constant(AnyConst::Type($ty.into())),
|
||||
false,
|
||||
);
|
||||
)*
|
||||
};
|
||||
|
||||
@@ -19,7 +19,7 @@ fn main() {
|
||||
file: PathBuf::from("../test.leaf"),
|
||||
})],
|
||||
) {
|
||||
println!("{}", err.message);
|
||||
println!("{:#?}", err);
|
||||
} else {
|
||||
println!("{:#?}", context.get_assembly(&ident));
|
||||
}
|
||||
|
||||
+310
-27
@@ -1,22 +1,38 @@
|
||||
use arcstr::Substr;
|
||||
use leaf_assembly::{
|
||||
assembly::Assembly,
|
||||
types::Type,
|
||||
values::{AnyConst, Value},
|
||||
functions::{
|
||||
Function,
|
||||
ir::{Cmp, FunctionBodyBuilder},
|
||||
},
|
||||
types::{Type, derivations::PtrT},
|
||||
values::{AnyConst, Int, Value, ValueFlags},
|
||||
};
|
||||
use leaf_parser::{
|
||||
SourceCode,
|
||||
ast::{self, ConstDecl, Expr, Ident},
|
||||
ast::{self, BinaryExpr, BinaryOp, ConstDecl, Expr, Ident, NamePattern, While},
|
||||
};
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use crate::error::*;
|
||||
|
||||
#[derive(Default)]
|
||||
struct ExpressionContext<'l, 'r> {
|
||||
decl_names: Option<&'r NamePattern>,
|
||||
builder: Option<&'r mut FunctionBodyBuilder<'l>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Variable<'l> {
|
||||
value: Value<'l>,
|
||||
mutable: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Scope<'l> {
|
||||
assembly: &'l Assembly<'l>,
|
||||
source: Arc<SourceCode>,
|
||||
values: HashMap<Substr, Option<Value<'l>>>,
|
||||
values: HashMap<Substr, Variable<'l>>,
|
||||
}
|
||||
|
||||
impl<'l> Scope<'l> {
|
||||
@@ -28,26 +44,49 @@ impl<'l> Scope<'l> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, name: Substr, value: Value<'l>) {
|
||||
self.values.insert(name, Some(value));
|
||||
pub fn insert(&mut self, name: Substr, value: Value<'l>, mutable: bool) {
|
||||
self.values.insert(name, Variable { value, mutable });
|
||||
}
|
||||
|
||||
pub fn declare_constants(&mut self, decl: &[ConstDecl]) {
|
||||
for val in decl {
|
||||
for Ident(name) in val.names.as_slice() {
|
||||
self.values.insert(name.clone(), None);
|
||||
self.values.insert(
|
||||
name.clone(),
|
||||
Variable {
|
||||
value: Value::Uninit,
|
||||
mutable: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn define_constants(&mut self, decl: &[ConstDecl]) -> Result<(), CompilationError> {
|
||||
for val in decl {
|
||||
let expr = self.compile_expression(&val.value)?;
|
||||
let expr = self.compile_expression(
|
||||
&val.value,
|
||||
&mut ExpressionContext {
|
||||
decl_names: Some(&val.names),
|
||||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
match &val.names {
|
||||
NamePattern::Single(ident) => {
|
||||
self.values.get_mut(&ident.0).unwrap().value = expr;
|
||||
}
|
||||
NamePattern::Tuple(_) => todo!(),
|
||||
NamePattern::List(_) => todo!(),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compile_expression(&self, expr: &Expr) -> Result<Value<'l>, CompilationError> {
|
||||
fn compile_expression(
|
||||
&mut self,
|
||||
expr: &Expr,
|
||||
ctx: &mut ExpressionContext<'l, '_>,
|
||||
) -> Result<Value<'l>, CompilationError> {
|
||||
match expr {
|
||||
Expr::Ident(Ident(name)) => match self.values.get(name) {
|
||||
None => Err(CompilationError {
|
||||
@@ -59,7 +98,10 @@ impl<'l> Scope<'l> {
|
||||
},
|
||||
cause: None,
|
||||
}),
|
||||
Some(None) => Err(CompilationError {
|
||||
Some(Variable {
|
||||
value: Value::Uninit,
|
||||
..
|
||||
}) => Err(CompilationError {
|
||||
kind: Kind::UninitializedSymbol,
|
||||
message: format!("Symbol `{name}` is not initialized at this time."),
|
||||
location: Location::Range {
|
||||
@@ -68,32 +110,273 @@ impl<'l> Scope<'l> {
|
||||
},
|
||||
cause: None,
|
||||
}),
|
||||
Some(Some(value)) => Ok(*value),
|
||||
Some(Variable { value, .. }) => Ok(*value),
|
||||
},
|
||||
Expr::Func(func) => self.compile_function(func).map_err(|err| CompilationError {
|
||||
kind: Kind::FunctionCompilationFailed,
|
||||
message: format!("Could not compile function."),
|
||||
location: Location::Range {
|
||||
file: self.source.clone(),
|
||||
range: func.text.range(),
|
||||
|
||||
Expr::Func(func) => self
|
||||
.compile_function(func, ctx)
|
||||
.map(|f| Value::Constant(AnyConst::Function(f)))
|
||||
.map_err(|err| CompilationError {
|
||||
kind: Kind::FunctionCompilationFailed,
|
||||
message: format!("Could not compile function."),
|
||||
location: Location::Range {
|
||||
file: self.source.clone(),
|
||||
range: func.text.range(),
|
||||
},
|
||||
cause: Some(Box::new(err)),
|
||||
}),
|
||||
|
||||
Expr::ConstDecl(decl) => self.compile_decl(&decl.names, &decl.value, false, ctx),
|
||||
Expr::VarDecl(decl) => self.compile_decl(&decl.names, &decl.value, true, ctx),
|
||||
|
||||
Expr::Number(n) => {
|
||||
macro_rules! parse_number {
|
||||
($ty: ty, $id: ident) => {
|
||||
match n.text.split_at_checked(2) {
|
||||
Some(("0b", value)) => <$ty>::from_str_radix(value, 2),
|
||||
Some(("0x", value)) => <$ty>::from_str_radix(value, 16),
|
||||
_ => <$ty>::from_str_radix(&n.text, 10),
|
||||
}
|
||||
.map(|v| Value::Constant(AnyConst::Int(Int::$id(v))))
|
||||
.map_err(|_| CompilationError {
|
||||
kind: Kind::InvalidInteger,
|
||||
message: format!("`{}` is not a valid integer.", n.text),
|
||||
location: Location::Range {
|
||||
file: self.source.clone(),
|
||||
range: n.text.range(),
|
||||
},
|
||||
cause: None,
|
||||
})
|
||||
};
|
||||
}
|
||||
match n.r#type.as_ref().map(|v| v.as_str()) {
|
||||
None => parse_number!(i128, ISize),
|
||||
Some("i8") => parse_number!(i8, I8),
|
||||
Some("i16") => parse_number!(i16, I16),
|
||||
Some("i32") => parse_number!(i32, I32),
|
||||
Some("i64") => parse_number!(i64, I64),
|
||||
Some("i128") => parse_number!(i128, I128),
|
||||
Some("isize") => parse_number!(i128, ISize),
|
||||
Some("u8") => parse_number!(u8, U8),
|
||||
Some("u16") => parse_number!(u16, U16),
|
||||
Some("u32") => parse_number!(u32, U32),
|
||||
Some("u64") => parse_number!(u64, U64),
|
||||
Some("u128") => parse_number!(u128, U128),
|
||||
Some("usize") => parse_number!(u128, USize),
|
||||
Some(ty) => {
|
||||
return Err(CompilationError {
|
||||
kind: Kind::InvalidIntegerType,
|
||||
message: format!("`{ty}` is not a valid integer type."),
|
||||
location: Location::Range {
|
||||
file: self.source.clone(),
|
||||
range: n.text.range(),
|
||||
},
|
||||
cause: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Expr::Binary(expr) => {
|
||||
let BinaryExpr {
|
||||
lhs: lhs_expr,
|
||||
rhs: rhs_expr,
|
||||
op,
|
||||
} = &**expr;
|
||||
|
||||
let mut lhs = self.compile_expression(lhs_expr, ctx)?;
|
||||
if lhs.flags().contains(ValueFlags::LValue) && !matches!(op, BinaryOp::Assign(_)) {
|
||||
lhs = ctx.builder.as_mut().unwrap().load(lhs).unwrap();
|
||||
}
|
||||
|
||||
let mut rhs = self.compile_expression(rhs_expr, ctx)?;
|
||||
if rhs.flags().contains(ValueFlags::LValue) {
|
||||
rhs = ctx.builder.as_mut().unwrap().load(rhs).unwrap();
|
||||
}
|
||||
|
||||
let builder = ctx.builder.as_mut().unwrap();
|
||||
match (lhs.ty(), rhs.ty(), op) {
|
||||
(Type::U32, Type::U32, BinaryOp::Add(_)) => Ok(builder.add(lhs, rhs).unwrap()),
|
||||
(Type::U32, Type::U32, BinaryOp::Mul(_)) => Ok(builder.mul(lhs, rhs).unwrap()),
|
||||
(Type::U32, Type::U32, BinaryOp::Lt(_)) => {
|
||||
Ok(builder.cmp(lhs, rhs, Cmp::Lt).unwrap())
|
||||
}
|
||||
(Type::Ptr(PtrT { base, mutable, .. }), ty, BinaryOp::Assign(_)) => {
|
||||
match *base == ty {
|
||||
true => Ok(builder.store(lhs, rhs).unwrap()),
|
||||
false => Err(CompilationError {
|
||||
kind: Kind::InvalidType,
|
||||
message: format!(
|
||||
"Cannot assign a value of type `{ty}` to a value of type `{base}`."
|
||||
),
|
||||
location: Location::Range {
|
||||
file: self.source.clone(),
|
||||
range: rhs_expr.range(),
|
||||
},
|
||||
cause: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
(a, b, _) => unimplemented!("{a} {op:?} {b} | {lhs:?} {op:?} {rhs:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
Expr::While(expr) => {
|
||||
let While { value, block } = &**expr;
|
||||
|
||||
let mut builder = ctx.builder.as_mut().unwrap();
|
||||
let cond_block = builder.create_block();
|
||||
let exec_block = builder.create_block();
|
||||
let exit_block = builder.create_block();
|
||||
|
||||
builder.jump(cond_block).unwrap();
|
||||
builder.set_current_block(cond_block);
|
||||
let condition = self.compile_expression(value, ctx)?;
|
||||
|
||||
builder = ctx.builder.as_mut().unwrap();
|
||||
builder.branch(condition, exec_block, exit_block).unwrap();
|
||||
builder.set_current_block(exec_block);
|
||||
|
||||
let mut scope = self.clone();
|
||||
let mut ctx = ExpressionContext {
|
||||
builder: Some(builder),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let mut last_expr = None;
|
||||
for expr in &block.0 {
|
||||
last_expr = Some(scope.compile_expression(expr, &mut ctx)?);
|
||||
}
|
||||
builder.jump(cond_block).unwrap();
|
||||
builder.set_current_block(exit_block);
|
||||
Ok(last_expr.unwrap_or(Value::Constant(AnyConst::Void)))
|
||||
}
|
||||
|
||||
Expr::Call {
|
||||
func,
|
||||
args: args_exprs,
|
||||
} => {
|
||||
let func = match self.compile_expression(func, ctx)? {
|
||||
Value::Constant(AnyConst::Function(func)) => func,
|
||||
_ => {
|
||||
return Err(CompilationError {
|
||||
kind: Kind::NotAFunction,
|
||||
message: "Value is not a function".into(),
|
||||
location: Location::Range {
|
||||
file: self.source.clone(),
|
||||
range: func.range(),
|
||||
},
|
||||
cause: None,
|
||||
});
|
||||
}
|
||||
};
|
||||
let mut args = Vec::with_capacity(args_exprs.len());
|
||||
for expr in args_exprs {
|
||||
let mut arg = self.compile_expression(expr, ctx)?;
|
||||
if arg.flags().contains(ValueFlags::LValue) {
|
||||
arg = ctx.builder.as_mut().unwrap().load(arg).unwrap();
|
||||
}
|
||||
args.push(arg);
|
||||
}
|
||||
let builder = ctx.builder.as_mut().unwrap();
|
||||
Ok(builder.call(func, args).unwrap())
|
||||
}
|
||||
|
||||
Expr::Type(expr) => match &**expr {
|
||||
ast::Type::Ptr { base, mutable } => match self.compile_expression(base, ctx)? {
|
||||
Value::Constant(AnyConst::Type(ty)) => {
|
||||
Ok(AnyConst::Type(Type::Ptr(ty.make_ptr(*mutable))).into())
|
||||
}
|
||||
_ => todo!(),
|
||||
},
|
||||
cause: Some(Box::new(err)),
|
||||
}),
|
||||
},
|
||||
|
||||
_ => todo!("{expr:#?}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_function(&self, func: &ast::Function) -> Result<Value<'l>, CompilationError> {
|
||||
let ret_ty = self.assert_type(self.compile_expression(&func.ret)?)?;
|
||||
let mut par_ty = Vec::with_capacity(func.args.len());
|
||||
for arg in &func.args {
|
||||
let ty = self.assert_type(self.compile_expression(&arg.r#type)?)?;
|
||||
fn compile_function(
|
||||
&mut self,
|
||||
ast: &ast::Function,
|
||||
ctx: &mut ExpressionContext<'l, '_>,
|
||||
) -> Result<&'l Function<'l>, CompilationError> {
|
||||
let ret_ty = match ast.ret.as_ref() {
|
||||
None => Value::Constant(AnyConst::Type(Type::Void)),
|
||||
Some(ty) => self.compile_expression(ty, ctx)?,
|
||||
};
|
||||
let ret_ty = self.assert_type(ret_ty)?;
|
||||
let mut par_ty = Vec::with_capacity(ast.args.len());
|
||||
for arg in &ast.args {
|
||||
let ty = self.compile_expression(&arg.r#type, ctx)?;
|
||||
let ty = self.assert_type(ty)?;
|
||||
par_ty.push(ty);
|
||||
}
|
||||
|
||||
let fn_ty = ret_ty.make_fn(par_ty);
|
||||
Ok(Value::Constant(AnyConst::Function(
|
||||
self.assembly.create_function(fn_ty),
|
||||
)))
|
||||
let func = self.assembly.create_function(fn_ty);
|
||||
if let Some(NamePattern::Single(func_name)) = &ctx.decl_names {
|
||||
func.name.set(func.ctx().intern_str(&func_name.0)).unwrap();
|
||||
if let Some(variable) = self.values.get_mut(func_name.as_str()) {
|
||||
variable.value = Value::Constant(AnyConst::Function(func));
|
||||
}
|
||||
};
|
||||
|
||||
let Some(block) = &ast.block else {
|
||||
return Ok(func);
|
||||
};
|
||||
|
||||
let mut scope = self.clone();
|
||||
for (i, arg) in ast.args.iter().enumerate() {
|
||||
scope.insert(arg.name.0.clone(), Value::Parameter(i, func), false);
|
||||
}
|
||||
|
||||
let mut builder = func.create_body().unwrap();
|
||||
let mut ctx = ExpressionContext {
|
||||
builder: Some(&mut builder),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let mut last_expr = None;
|
||||
for expr in &block.0 {
|
||||
last_expr = Some(scope.compile_expression(expr, &mut ctx)?);
|
||||
}
|
||||
|
||||
if !builder.current_block().has_termination() {
|
||||
builder.ret(last_expr).unwrap();
|
||||
}
|
||||
|
||||
builder.build().unwrap();
|
||||
|
||||
Ok(func)
|
||||
}
|
||||
|
||||
fn compile_decl(
|
||||
&mut self,
|
||||
names: &NamePattern,
|
||||
value: &Expr,
|
||||
mutable: bool,
|
||||
ctx: &mut ExpressionContext<'l, '_>,
|
||||
) -> Result<Value<'l>, CompilationError> {
|
||||
let mut sub_ctx = ExpressionContext {
|
||||
decl_names: Some(names),
|
||||
builder: ctx.builder.as_mut().map(|v| &mut **v),
|
||||
};
|
||||
let mut value = self.compile_expression(value, &mut sub_ctx)?;
|
||||
if mutable {
|
||||
let builder = sub_ctx.builder.unwrap();
|
||||
let variable = builder.stack_alloc(value.ty()).unwrap();
|
||||
builder.store(variable, value).unwrap();
|
||||
value = variable;
|
||||
}
|
||||
match names {
|
||||
NamePattern::Single(ident) => {
|
||||
self.values
|
||||
.insert(ident.0.clone(), Variable { value, mutable });
|
||||
}
|
||||
NamePattern::Tuple(_) => todo!(),
|
||||
NamePattern::List(_) => todo!(),
|
||||
}
|
||||
Ok(AnyConst::Void.into())
|
||||
}
|
||||
|
||||
fn assert_type(&self, val: Value<'l>) -> Result<Type<'l>, CompilationError> {
|
||||
|
||||
@@ -7,5 +7,7 @@ edition = "2024"
|
||||
fxhash = "0.2.1"
|
||||
leaf_allocators = { path = "../allocators" }
|
||||
leaf_assembly = { path = "../assembly" }
|
||||
leaf_compiler = { path = "../compiler" }
|
||||
leaf_parser = { path = "../parser" }
|
||||
scc = "3.3.7"
|
||||
smallvec = "1.15.1"
|
||||
|
||||
@@ -6,7 +6,7 @@ use leaf_assembly::{
|
||||
ir::{Cmp, Instruction, InstructionVariant},
|
||||
},
|
||||
types::{IntT, Type},
|
||||
values::{AnyConst, Const, Int, Value},
|
||||
values::{AnyConst, Int, Value},
|
||||
};
|
||||
use scc::HashMap;
|
||||
use std::{alloc::Layout, fmt::Debug, ops::Range, sync::Arc};
|
||||
@@ -246,7 +246,7 @@ impl<'l> InstructionCacheEntry<'l> {
|
||||
Value::Instruction(i) => {
|
||||
ranges.push(memory_ranges[&i.id()].clone());
|
||||
}
|
||||
_ => todo!("Unimplemented variant `{arg}`."),
|
||||
_ => todo!("Unimplemented variant `{arg:?}`."),
|
||||
}
|
||||
}
|
||||
opcodes.push(OpCode::Call(
|
||||
|
||||
+33
-55
@@ -1,66 +1,44 @@
|
||||
use leaf_allocators::SyncArenaAllocator;
|
||||
use leaf_assembly::assembly::{AssemblyIdentifier, Context, Version};
|
||||
use leaf_assembly::functions::ir::Cmp;
|
||||
use leaf_assembly::types::Type;
|
||||
use leaf_assembly::values::Int;
|
||||
use leaf_assembly::assembly::{AssemblyIdentifier, Version};
|
||||
use leaf_compiler::CompilationContext;
|
||||
use leaf_interpreter::interpreter::{AnyValue, Error, Interpreter, NativeFunction};
|
||||
use leaf_parser::SourceCode;
|
||||
use std::ffi::CStr;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
fn main() {
|
||||
let allocator = SyncArenaAllocator::default();
|
||||
let context = Context::new(&allocator);
|
||||
let assembly = context.get_or_create_assembly(AssemblyIdentifier {
|
||||
let context = CompilationContext::new(&allocator);
|
||||
let ident = AssemblyIdentifier {
|
||||
version: Version::default(),
|
||||
name: "test".into(),
|
||||
});
|
||||
|
||||
let puts = assembly.create_function(Type::Void.make_fn([Type::U8.make_ptr(false).into()]));
|
||||
|
||||
let print_u32 = assembly.create_function(Type::Void.make_fn([Type::U32.into()]));
|
||||
|
||||
let random_func = {
|
||||
let func = assembly.create_function(Type::U32.make_fn([]));
|
||||
let mut builder = func.create_body().unwrap();
|
||||
|
||||
let loop_check = builder.create_block();
|
||||
let loop_body = builder.create_block();
|
||||
let loop_end = builder.create_block();
|
||||
|
||||
let var0 = builder.stack_alloc(Type::U32).unwrap();
|
||||
let var1 = builder.stack_alloc(Type::U32).unwrap();
|
||||
|
||||
builder.store(var0, Int::U32(42).into()).unwrap();
|
||||
|
||||
builder.store(var1, Int::U32(0u32).into()).unwrap();
|
||||
|
||||
builder.jump(loop_check).unwrap();
|
||||
builder.set_current_block(loop_check);
|
||||
|
||||
let a = builder.load(var0).unwrap();
|
||||
let b = builder.load(var1).unwrap();
|
||||
let c = builder.add(a, b).unwrap();
|
||||
builder.call(print_u32, vec![c]).unwrap();
|
||||
|
||||
let cond = builder.cmp(c, Int::U32(69u32).into(), Cmp::Lt).unwrap();
|
||||
builder.branch(cond, loop_body, loop_end).unwrap();
|
||||
|
||||
builder.set_current_block(loop_body);
|
||||
let v = builder.load(var1).unwrap();
|
||||
let v = builder.add(v, Int::U32(1u32).into()).unwrap();
|
||||
builder.store(var1, v).unwrap();
|
||||
builder.jump(loop_check).unwrap();
|
||||
|
||||
builder.set_current_block(loop_end);
|
||||
let v = builder.load(var1).unwrap();
|
||||
builder.ret(Some(v)).unwrap();
|
||||
|
||||
let body = builder.build().unwrap();
|
||||
println!("{body:#?}");
|
||||
func
|
||||
name: "interpreter.il".into(),
|
||||
};
|
||||
context
|
||||
.extend(
|
||||
ident.clone(),
|
||||
&[Arc::new(SourceCode {
|
||||
text: std::fs::read_to_string("../test.leaf").unwrap().into(),
|
||||
file: PathBuf::from("../test.leaf"),
|
||||
})],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut interpreter = Interpreter::new(context);
|
||||
let mut interpreter = Interpreter::new(&context);
|
||||
let assembly = context.get_assembly(&ident).unwrap();
|
||||
|
||||
let puts = assembly
|
||||
.find_function(|f| f.name.get() == Some(&"puts"))
|
||||
.unwrap();
|
||||
|
||||
let print_u32 = assembly
|
||||
.find_function(|f| f.name.get() == Some(&"print_u32"))
|
||||
.unwrap();
|
||||
|
||||
let main = assembly
|
||||
.find_function(|f| f.name.get() == Some(&"main"))
|
||||
.unwrap();
|
||||
|
||||
interpreter.register_function(
|
||||
puts,
|
||||
@@ -91,7 +69,7 @@ fn main() {
|
||||
|
||||
{
|
||||
let now = Instant::now();
|
||||
let result = interpreter.run(random_func, vec![]);
|
||||
let result = interpreter.run(main, vec![]);
|
||||
let elapsed = now.elapsed();
|
||||
println!("Ret Value: {result:?}");
|
||||
println!("Cold Time: {:?}", elapsed)
|
||||
@@ -101,7 +79,7 @@ fn main() {
|
||||
let mut duration = Duration::default();
|
||||
for _ in 0..LOOPS {
|
||||
let now = Instant::now();
|
||||
let _ = interpreter.run(random_func, vec![]);
|
||||
let _ = interpreter.run(main, vec![]);
|
||||
duration += now.elapsed();
|
||||
}
|
||||
println!("Warm Time: {:?}", duration / LOOPS);
|
||||
|
||||
+38
-9
@@ -1,3 +1,5 @@
|
||||
use std::ops::Range;
|
||||
|
||||
use arcstr::Substr;
|
||||
use derive_more::Deref;
|
||||
|
||||
@@ -32,6 +34,8 @@ pub enum Expr {
|
||||
Block(Block),
|
||||
#[debug("{_0:?}")]
|
||||
Func(Box<Function>),
|
||||
#[debug("{_0:?}")]
|
||||
Type(Box<Type>),
|
||||
|
||||
#[debug("{_0:?}")]
|
||||
ConstDecl(Box<ConstDecl>),
|
||||
@@ -39,6 +43,8 @@ pub enum Expr {
|
||||
VarDecl(Box<VarDecl>),
|
||||
#[debug("{_0:?}")]
|
||||
For(Box<For>),
|
||||
#[debug("{_0:?}")]
|
||||
While(Box<While>),
|
||||
|
||||
Call {
|
||||
func: Box<Expr>,
|
||||
@@ -46,6 +52,14 @@ pub enum Expr {
|
||||
},
|
||||
}
|
||||
|
||||
impl Expr {
|
||||
pub fn range(&self) -> Range<usize> {
|
||||
match self {
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BinaryExpr {
|
||||
pub lhs: Expr,
|
||||
@@ -62,14 +76,23 @@ pub struct IndexingExpr {
|
||||
#[rustfmt::skip]
|
||||
#[derive(derive_more::Debug)]
|
||||
pub enum BinaryOp {
|
||||
#[debug("{_0:?}")] Add(Substr),
|
||||
#[debug("{_0:?}")] Sub(Substr),
|
||||
#[debug("{_0:?}")] Mul(Substr),
|
||||
#[debug("{_0:?}")] Div(Substr),
|
||||
#[debug("{_0:?}")] Mod(Substr),
|
||||
#[debug("{_0:?}")] Dot(Substr),
|
||||
#[debug("{_0:?}")] Range(Substr),
|
||||
#[debug("{_0:?}")] Assign(Substr),
|
||||
#[debug("{_0}")] Add(Substr),
|
||||
#[debug("{_0}")] Sub(Substr),
|
||||
#[debug("{_0}")] Mul(Substr),
|
||||
#[debug("{_0}")] Div(Substr),
|
||||
#[debug("{_0}")] Mod(Substr),
|
||||
#[debug("{_0}")] Dot(Substr),
|
||||
#[debug("{_0}")] Lt(Substr),
|
||||
#[debug("{_0}")] Gt(Substr),
|
||||
#[debug("{_0}")] Le(Substr),
|
||||
#[debug("{_0}")] Ge(Substr),
|
||||
#[debug("{_0}")] Range(Substr),
|
||||
#[debug("{_0}")] Assign(Substr),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Type {
|
||||
Ptr { base: Expr, mutable: bool },
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -107,7 +130,7 @@ impl NamePattern {
|
||||
pub struct Function {
|
||||
pub text: Substr,
|
||||
pub args: Vec<NameValuePair>,
|
||||
pub ret: Expr,
|
||||
pub ret: Option<Expr>,
|
||||
pub block: Option<Block>,
|
||||
}
|
||||
|
||||
@@ -133,6 +156,12 @@ pub struct For {
|
||||
pub block: Block,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct While {
|
||||
pub value: Expr,
|
||||
pub block: Block,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CompilationUnit {
|
||||
pub imports: Vec<Import>,
|
||||
|
||||
+12
-1
@@ -84,14 +84,21 @@ peg::parser! {
|
||||
--
|
||||
lhs:(@) __ op:$("..") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Range(op), rhs })) }
|
||||
--
|
||||
lhs:(@) __ op:$("<") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Lt(op), rhs })) }
|
||||
lhs:(@) __ op:$(">") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Gt(op), rhs })) }
|
||||
lhs:(@) __ op:$("<=") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Le(op), rhs })) }
|
||||
lhs:(@) __ op:$(">=") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Ge(op), rhs })) }
|
||||
--
|
||||
block:block() { Expr::Block(block)}
|
||||
for_loop:for_loop() { Expr::For(Box::new(for_loop))}
|
||||
while_loop:while_loop() { Expr::While(Box::new(while_loop))}
|
||||
func:func() { Expr::Func(Box::new(func))}
|
||||
var_decl:var_decl() { Expr::VarDecl(Box::new(var_decl)) }
|
||||
const_decl:const_decl() { Expr::ConstDecl(Box::new(const_decl)) }
|
||||
"(" __ tuple:(expr() **<2,> ("," __)) __ ")" { Expr::Tuple(tuple) }
|
||||
"[" __ list:(expr() **<0,> ("," __)) __ "]" { Expr::List(list) }
|
||||
"(" __ v:expr() __ ")" { v }
|
||||
"*" __ m:"mut"? __ v:expr() { Expr::Type(Box::new(Type::Ptr { base:v, mutable: m.is_some() })) }
|
||||
v:string() { Expr::String(v) }
|
||||
v:number() { Expr::Number(v) }
|
||||
v:ident() { Expr::Ident(v) }
|
||||
@@ -101,7 +108,7 @@ peg::parser! {
|
||||
= "{" __ exprs:(i:expr() statement_separator() {i})* __ "}" { Block(exprs) }
|
||||
|
||||
rule func() -> Function
|
||||
= s:position!() t:$"fn" __ "(" __ args:name_value_pairs() __ ")" __ ret:expr() __ block:block()? e:position!()
|
||||
= s:position!() t:$"fn" __ "(" __ args:name_value_pairs() __ ")" __ ret:("->" __ e:expr() {e})? __ block:block()? e:position!()
|
||||
{ Function { args, ret, block, text: t.parent().substr(s..e), } }
|
||||
|
||||
rule name_value_pair() -> NameValuePair
|
||||
@@ -130,6 +137,10 @@ peg::parser! {
|
||||
"for" _ names:name_pattern() _ "in" _ value:expr() _ block:block()
|
||||
{ For { names, value, block } }
|
||||
|
||||
rule while_loop() -> While =
|
||||
"while" _ value:expr() _ block:block()
|
||||
{ While { value, block } }
|
||||
|
||||
pub rule compilation_unit() -> CompilationUnit =
|
||||
__ imports:(i:import() statement_separator() {i})*
|
||||
__ decls:(d:const_decl() statement_separator() {d})*
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
[toolchain]
|
||||
channel = "1.91.0"
|
||||
components = ["clippy", "rustfmt"]
|
||||
profile = "default"
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
import leaf.reflection.comptime
|
||||
puts :: fn(v: *u8) -> i32;
|
||||
print_u32 :: fn(v: u32);
|
||||
|
||||
add :: fn(a: u32, b: u32) u32 {
|
||||
a + b
|
||||
print_up_to :: fn(max: u32) {
|
||||
i := 0u32
|
||||
while i < max {
|
||||
print_u32(i)
|
||||
i = i + 1u32
|
||||
}
|
||||
}
|
||||
|
||||
Vector :: fn(T: type, count: usize) type {
|
||||
NAMES :: ["x", "y", "z", "w"]
|
||||
|
||||
ty := TypeBuilder.struct()
|
||||
for i in 0..count {
|
||||
ty.push(Field {
|
||||
name: NAMES[i],
|
||||
type: T,
|
||||
flags: FieldFlags.Public
|
||||
})
|
||||
}
|
||||
|
||||
ty.build()
|
||||
main :: fn() {
|
||||
print_up_to(42u32)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user