aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEdvard Thörnros <edvard.thornros@gmail.com>2021-02-02 20:22:02 +0100
committerEdvard Thörnros <edvard.thornros@gmail.com>2021-02-02 20:22:02 +0100
commit09bc674a9126d0481834163afddfceb18a4e3acd (patch)
tree2760ee16d958ea6ace5001845fc498f09e32e1a2 /src
parent5b9de776ba7de654fa92bee7c38fb30d7929405d (diff)
downloadsylt-09bc674a9126d0481834163afddfceb18a4e3acd.tar.gz
reorder some stuff
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs915
1 files changed, 456 insertions, 459 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 62a2a81..e1b7f89 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -57,302 +57,86 @@ pub fn run(tokens: TokenStream, path: &Path, print: bool, functions: Vec<(String
}
}
-#[cfg(test)]
-mod tests {
- use std::path::Path;
-
- use crate::error::ErrorKind;
-
- use super::{run_file, run_string};
+pub type RustFunction = fn(&[Value], bool) -> Result<Value, ErrorKind>;
- #[macro_export]
- macro_rules! assert_errs {
- ($result:expr, [ $( $kind:pat ),* ]) => {
- eprintln!("{} => {:?}", stringify!($result), $result);
- assert!(matches!(
- $result.unwrap_err().as_slice(),
- &[$($crate::error::Error {
- kind: $kind,
- file: _,
- line: _,
- message: _,
- },
- )*]
- ))
- };
- }
+#[derive(Debug, Clone)]
+pub enum Type {
+ Void,
+ UnknownType,
+ Int,
+ Float,
+ Bool,
+ String,
+ Tuple(Vec<Type>),
+ Function(Vec<Type>, Box<Type>),
+ Blob(usize),
+ BlobInstance(usize),
+}
- #[macro_export]
- macro_rules! test_string {
- ($fn:ident, $prog:literal) => {
- #[test]
- fn $fn() {
- $crate::run_string($prog, true, Vec::new()).unwrap();
- }
- };
- ($fn:ident, $prog:literal, $errs:tt) => {
- #[test]
- fn $fn() {
- $crate::assert_errs!($crate::run_string($prog, true, Vec::new()), $errs);
+impl PartialEq for Type {
+ fn eq(&self, other: &Self) -> bool {
+ match (self, other) {
+ (Type::Void, Type::Void) => true,
+ (Type::BlobInstance(a), Type::BlobInstance(b)) => a == b,
+ (Type::Blob(a), Type::Blob(b)) => a == b,
+ (Type::Int, Type::Int) => true,
+ (Type::Float, Type::Float) => true,
+ (Type::Bool, Type::Bool) => true,
+ (Type::String, Type::String) => true,
+ (Type::Tuple(a), Type::Tuple(b)) => {
+ a.iter().zip(b.iter()).all(|(a, b)| a == b)
}
+ (Type::Function(a_args, a_ret), Type::Function(b_args, b_ret)) =>
+ a_args == b_args && a_ret == b_ret,
+ _ => false,
}
}
+}
- #[macro_export]
- macro_rules! test_file {
- ($fn:ident, $path:literal) => {
- #[test]
- fn $fn() {
- let file = Path::new($path);
- run_file(&file, true, Vec::new()).unwrap();
+impl From<&Value> for Type {
+ fn from(value: &Value) -> Type {
+ match value {
+ Value::BlobInstance(i, _) => Type::BlobInstance(*i),
+ Value::Blob(i) => Type::Blob(*i),
+ Value::Tuple(v) => {
+ Type::Tuple(v.iter().map(|x| Type::from(x)).collect())
}
- };
+ Value::Int(_) => Type::Int,
+ Value::Float(_) => Type::Float,
+ Value::Bool(_) => Type::Bool,
+ Value::String(_) => Type::String,
+ Value::Function(_, block) => block.borrow().ty.clone(),
+ _ => Type::Void,
+ }
}
+}
- #[test]
- fn unreachable_token() {
- assert_errs!(run_string("<!>\n", true, Vec::new()), [ErrorKind::Unreachable]);
+impl Type {
+ pub fn is_unkown(&self) -> bool {
+ match self {
+ Type::UnknownType => true,
+ _ => false,
+ }
}
- macro_rules! test_multiple {
- ($mod:ident, $( $fn:ident : $prog:literal ),+ $( , )? ) => {
- mod $mod {
- $( test_string!($fn, $prog); )+
+ pub fn as_value(&self) -> Value {
+ match self {
+ Type::Void => Value::Nil,
+ Type::Blob(i) => Value::Blob(*i),
+ Type::BlobInstance(i) => Value::BlobInstance(*i, Rc::new(RefCell::new(Vec::new()))),
+ Type::Tuple(fields) => {
+ Value::Tuple(Rc::new(fields.iter().map(|x| x.as_value()).collect()))
}
+ Type::UnknownType => Value::Unkown,
+ Type::Int => Value::Int(1),
+ Type::Float => Value::Float(1.0),
+ Type::Bool => Value::Bool(true),
+ Type::String => Value::String(Rc::new("".to_string())),
+ Type::Function(_, _) => Value::Function(
+ Vec::new(),
+ Rc::new(RefCell::new(Block::from_type(self)))),
}
}
-
- test_multiple!(
- order_of_operations,
- terms_and_factors: "1 + 1 * 2 <=> 3
- 1 * 2 + 3 <=> 5",
- in_rhs: "5 <=> 1 * 2 + 3",
- parenthesis: "(1 + 2) * 3 <=> 9",
- negation: "-1 <=> 0 - 1
- -1 + 2 <=> 1
- -(1 + 2) <=> -3
- 1 + -1 <=> 0
- 2 * -1 <=> -2",
- );
-
- test_multiple!(
- variables,
- single_variable: "a := 1
- a <=> 1",
- two_variables: "a := 1
- b := 2
- a <=> 1
- b <=> 2",
- stack_ordering: "a := 1
- b := 2
- b <=> 2
- a <=> 1",
- assignment: "a := 1
- b := 2
- a = b
- a <=> 2
- b <=> 2",
- );
-
- test_multiple!(
- if_,
- compare_constants_equality: "if 1 == 2 {
- <!>
- }",
- compare_constants_unequality: "if 1 != 1 {
- <!>
- }",
- compare_variable: "a := 1
- if a == 0 {
- <!>
- }
- if a != 1 {
- <!>
- }",
- else_: "a := 1
- res := 0
- if a == 0 {
- <!>
- } else {
- res = 1
- }
- res <=> 1",
- else_if: "a := 1
- res := 0
- if a == 0 {
- <!>
- } else if a == 1 {
- res = 1
- } else {
- <!>
- }
- res <=> 1",
- );
-
- test_multiple!(
- fun,
- simplest: "f := fn {}
- f()",
- param_1: "f := fn a: int {}
- f(1)",
- return_1: "f := fn -> int {
- ret 1
- }
- f() <=> 1",
- param_and_return: "f := fn a: int -> int {
- ret a * 2
- }
- f(1) <=> 2
- f(5) <=> 10",
- param_2: "add := fn a: int, b: int -> int {
- ret a + b
- }
- add(1, 1) <=> 2
- add(10, 20) <=> 30",
- calls_inside_calls: "one := fn -> int {
- ret 1
- }
- add := fn a: int, b: int -> int {
- ret a + b
- }
- add(one(), one()) <=> 2
- add(add(one(), one()), one()) <=> 3
- add(one(), add(one(), one())) <=> 3",
- passing_functions: "g := fn -> int {
- ret 1
- }
- f := fn inner: fn -> int -> int {
- ret inner()
- }
- f(g) <=> 1",
- passing_functions_mixed: "g := fn a: int -> int {
- ret a * 2
- }
- f := fn inner: fn int -> int, a: int -> int {
- ret inner(a)
- }
- f(g, 2) <=> 4",
- multiple_returns: "f := fn a: int -> int {
- if a == 1 {
- ret 2
- } else {
- ret 3
- }
- }
- f(0) <=> 3
- f(1) <=> 2
- f(2) <=> 3",
- precedence: "f := fn a: int, b: int -> int {
- ret a + b
- }
- 1 + f(2, 3) <=> 6
- 2 * f(2, 3) <=> 10
- f(2, 3) - (2 + 3) <=> 0",
- factorial: "factorial : fn int -> int = fn n: int -> int {
- if n <= 1 {
- ret 1
- }
- ret n * factorial(n - 1)
- }
- factorial(5) <=> 120
- factorial(6) <=> 720
- factorial(12) <=> 479001600",
-
- returning_closures: "
-f : fn -> fn -> int = fn -> fn -> int {
- x : int = 0
- f := fn -> int {
- x = x + 1
- ret x
- }
- f() <=> 1
- ret f
-}
-
-a := f()
-b := f()
-
-a() <=> 2
-a() <=> 3
-
-b() <=> 2
-b() <=> 3
-
-a() <=> 4
-"
-
- //TODO this tests doesn't terminate in proper time if we print blocks and ops
- /*
- fibonacci: "fibonacci : fn int -> int = fn n: int -> int {
- if n == 0 {
- ret 0
- } else if n == 1 {
- ret 1
- } else if n < 0 {
- <!>
- }
- ret fibonacci(n - 1) + fibonacci(n - 2)
- }
- fibonacci(10) <=> 55
- fibonacci(20) <=> 6765"
- */
- );
-
- test_multiple!(
- blob,
- simple: "blob A {}",
- instantiate: "blob A {}
- a := A()",
- field: "blob A { a: int }",
- field_assign: "blob A { a: int }
- a := A()
- a.a = 2",
- field_get: "blob A { a: int }
- a := A()
- a.a = 2
- a.a <=> 2
- 2 <=> a.a",
- multiple_fields: "blob A {
- a: int
- b: int
- }
- a := A()
- a.a = 2
- a.b = 3
- a.a + a.b <=> 5
- 5 <=> a.a + a.b"
- );
-
- test_multiple!(tuples,
- add: "(1, 2, 3, 4) + (4, 3, 2, 1) <=> (5, 5, 5, 5)",
- sub: "(1, -2, 3, -4) - (4, 3, -2, -1) <=> (-3, 1, 1, -5)",
- mul: "(0, 1, 2) * (2, 3, 4) <=> (0, 3, 8)",
- types: "a: (int, float, int) = (1, 1., 1)",
- more_types: "a: (str, bool, int) = (\"abc\", true, 1)",
- );
-
- test_file!(scoping, "progs/tests/scoping.sy");
- test_file!(for_, "progs/tests/for.sy");
-
- test_multiple!(
- op_assign,
- add: "a := 1\na += 1\na <=> 2",
- sub: "a := 2\na -= 1\na <=> 1",
- mul: "a := 2\na *= 2\na <=> 4",
- div: "a := 2\na /= 2\na <=> 1",
- cluster: "
-blob A { a: int }
-a := A()
-a.a = 0
-a.a += 1
-a.a <=> 1
-a.a *= 2
-a.a <=> 2
-a.a /= 2
-a.a <=> 1
-a.a -= 1
-a.a <=> 0"
- );
}
#[derive(Clone)]
@@ -370,6 +154,46 @@ pub enum Value {
Nil,
}
+impl Debug for Value {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ Value::Blob(i) => write!(fmt, "(blob {})", i),
+ Value::BlobInstance(i, v) => write!(fmt, "(inst {} {:?})", i, v),
+ Value::Float(f) => write!(fmt, "(float {})", f),
+ Value::Int(i) => write!(fmt, "(int {})", i),
+ Value::Bool(b) => write!(fmt, "(bool {})", b),
+ Value::String(s) => write!(fmt, "(string \"{}\")", s),
+ Value::Function(_, block) => write!(fmt, "(fn {}: {:?})", block.borrow().name, block.borrow().ty),
+ Value::ExternFunction(slot) => write!(fmt, "(extern fn {})", slot),
+ Value::Unkown => write!(fmt, "(unkown)"),
+ Value::Nil => write!(fmt, "(nil)"),
+ Value::Tuple(v) => write!(fmt, "({:?})", v),
+ }
+ }
+}
+
+impl Value {
+ fn identity(self) -> Self {
+ match self {
+ Value::Float(_) => Value::Float(1.0),
+ Value::Int(_) => Value::Int(1),
+ Value::Bool(_) => Value::Bool(true),
+ a => a,
+ }
+ }
+
+ fn is_nil(&self) -> bool {
+ match self {
+ Value::Nil => true,
+ _ => false,
+ }
+ }
+
+ fn as_type(&self) -> Type {
+ Type::from(self)
+ }
+}
+
#[derive(Clone, Debug)]
pub struct UpValue {
slot: usize,
@@ -411,24 +235,83 @@ impl UpValue {
}
}
-impl Debug for Value {
- fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match self {
- Value::Blob(i) => write!(fmt, "(blob {})", i),
- Value::BlobInstance(i, v) => write!(fmt, "(inst {} {:?})", i, v),
- Value::Float(f) => write!(fmt, "(float {})", f),
- Value::Int(i) => write!(fmt, "(int {})", i),
- Value::Bool(b) => write!(fmt, "(bool {})", b),
- Value::String(s) => write!(fmt, "(string \"{}\")", s),
- Value::Function(_, block) => write!(fmt, "(fn {}: {:?})", block.borrow().name, block.borrow().ty),
- Value::ExternFunction(slot) => write!(fmt, "(extern fn {})", slot),
- Value::Unkown => write!(fmt, "(unkown)"),
- Value::Nil => write!(fmt, "(nil)"),
- Value::Tuple(v) => write!(fmt, "({:?})", v),
+#[derive(Debug, Clone)]
+pub struct Blob {
+ pub name: String,
+
+ pub name_to_field: HashMap<String, (usize, Type)>,
+}
+
+impl Blob {
+ pub fn new(name: &str) -> Self {
+ Self {
+ name: String::from(name),
+ name_to_field: HashMap::new(),
+ }
+ }
+
+ pub fn add_field(&mut self, name: &str, ty: Type) -> Result<(), ()> {
+ let size = self.name_to_field.len();
+ let entry = self.name_to_field.entry(String::from(name));
+ if matches!(entry, Entry::Occupied(_)) {
+ Err(())
+ } else {
+ entry.or_insert((size, ty));
+ Ok(())
}
}
}
+#[derive(Debug, Clone)]
+pub enum Op {
+ Illegal,
+
+ Pop,
+ PopUpvalue,
+ Copy,
+ Constant(Value),
+ Tuple(usize),
+
+ Index,
+ Get(String),
+ Set(String),
+
+ Add,
+ Sub,
+ Mul,
+ Div,
+ Neg,
+
+ And,
+ Or,
+ Not,
+
+ Jmp(usize),
+ JmpFalse(usize),
+
+ Equal, // ==
+ Less, // <
+ Greater, // >
+
+ Assert,
+ Unreachable,
+
+ ReadLocal(usize),
+ AssignLocal(usize),
+
+ ReadUpvalue(usize),
+ AssignUpvalue(usize),
+
+ Define(Type),
+
+ Call(usize),
+
+ Print,
+
+ Return,
+ Yield,
+}
+
mod op {
use super::Value;
use std::rc::Rc;
@@ -528,80 +411,6 @@ mod op {
_ => Value::Nil,
}
}
-
-}
-
-
-impl Value {
- fn identity(self) -> Self {
- match self {
- Value::Float(_) => Value::Float(1.0),
- Value::Int(_) => Value::Int(1),
- Value::Bool(_) => Value::Bool(true),
- a => a,
- }
- }
-
- fn is_nil(&self) -> bool {
- match self {
- Value::Nil => true,
- _ => false,
- }
- }
-
- fn as_type(&self) -> Type {
- Type::from(self)
- }
-}
-
-#[derive(Debug, Clone)]
-pub enum Op {
- Illegal,
-
- Pop,
- PopUpvalue,
- Copy,
- Constant(Value),
- Tuple(usize),
-
- Index,
- Get(String),
- Set(String),
-
- Add,
- Sub,
- Mul,
- Div,
- Neg,
-
- And,
- Or,
- Not,
-
- Jmp(usize),
- JmpFalse(usize),
-
- Equal, // ==
- Less, // <
- Greater, // >
-
- Assert,
- Unreachable,
-
- ReadLocal(usize),
- AssignLocal(usize),
-
- ReadUpvalue(usize),
- AssignUpvalue(usize),
-
- Define(Type),
-
- Call(usize),
-
- Print,
-
- Return,
- Yield,
}
#[derive(Debug)]
@@ -717,7 +526,6 @@ impl Block {
}
}
-
#[derive(Clone)]
pub struct Prog {
pub blocks: Vec<Rc<RefCell<Block>>>,
@@ -725,111 +533,300 @@ pub struct Prog {
pub functions: Vec<RustFunction>,
}
-#[derive(Debug, Clone)]
-pub enum Type {
- Void,
- UnknownType,
- Int,
- Float,
- Bool,
- String,
- Tuple(Vec<Type>),
- Function(Vec<Type>, Box<Type>),
- Blob(usize),
- BlobInstance(usize),
-}
+#[cfg(test)]
+mod tests {
+ use std::path::Path;
-impl PartialEq for Type {
- fn eq(&self, other: &Self) -> bool {
- match (self, other) {
- (Type::Void, Type::Void) => true,
- (Type::BlobInstance(a), Type::BlobInstance(b)) => a == b,
- (Type::Blob(a), Type::Blob(b)) => a == b,
- (Type::Int, Type::Int) => true,
- (Type::Float, Type::Float) => true,
- (Type::Bool, Type::Bool) => true,
- (Type::String, Type::String) => true,
- (Type::Tuple(a), Type::Tuple(b)) => {
- a.iter().zip(b.iter()).all(|(a, b)| a == b)
+ use crate::error::ErrorKind;
+
+ use super::{run_file, run_string};
+
+ #[macro_export]
+ macro_rules! assert_errs {
+ ($result:expr, [ $( $kind:pat ),* ]) => {
+ eprintln!("{} => {:?}", stringify!($result), $result);
+ assert!(matches!(
+ $result.unwrap_err().as_slice(),
+ &[$($crate::error::Error {
+ kind: $kind,
+ file: _,
+ line: _,
+ message: _,
+ },
+ )*]
+ ))
+ };
+ }
+
+ #[macro_export]
+ macro_rules! test_string {
+ ($fn:ident, $prog:literal) => {
+ #[test]
+ fn $fn() {
+ $crate::run_string($prog, true, Vec::new()).unwrap();
+ }
+ };
+ ($fn:ident, $prog:literal, $errs:tt) => {
+ #[test]
+ fn $fn() {
+ $crate::assert_errs!($crate::run_string($prog, true, Vec::new()), $errs);
}
- (Type::Function(a_args, a_ret), Type::Function(b_args, b_ret)) =>
- a_args == b_args && a_ret == b_ret,
- _ => false,
}
}
-}
-impl From<&Value> for Type {
- fn from(value: &Value) -> Type {
- match value {
- Value::BlobInstance(i, _) => Type::BlobInstance(*i),
- Value::Blob(i) => Type::Blob(*i),
- Value::Tuple(v) => {
- Type::Tuple(v.iter().map(|x| Type::from(x)).collect())
+ #[macro_export]
+ macro_rules! test_file {
+ ($fn:ident, $path:literal) => {
+ #[test]
+ fn $fn() {
+ let file = Path::new($path);
+ run_file(&file, true, Vec::new()).unwrap();
}
- Value::Int(_) => Type::Int,
- Value::Float(_) => Type::Float,
- Value::Bool(_) => Type::Bool,
- Value::String(_) => Type::String,
- Value::Function(_, block) => block.borrow().ty.clone(),
- _ => Type::Void,
- }
+ };
}
-}
-impl Type {
- pub fn is_unkown(&self) -> bool {
- match self {
- Type::UnknownType => true,
- _ => false,
- }
+ #[test]
+ fn unreachable_token() {
+ assert_errs!(run_string("<!>\n", true, Vec::new()), [ErrorKind::Unreachable]);
}
- pub fn as_value(&self) -> Value {
- match self {
- Type::Void => Value::Nil,
- Type::Blob(i) => Value::Blob(*i),
- Type::BlobInstance(i) => Value::BlobInstance(*i, Rc::new(RefCell::new(Vec::new()))),
- Type::Tuple(fields) => {
- Value::Tuple(Rc::new(fields.iter().map(|x| x.as_value()).collect()))
+ macro_rules! test_multiple {
+ ($mod:ident, $( $fn:ident : $prog:literal ),+ $( , )? ) => {
+ mod $mod {
+ $( test_string!($fn, $prog); )+
}
- Type::UnknownType => Value::Unkown,
- Type::Int => Value::Int(1),
- Type::Float => Value::Float(1.0),
- Type::Bool => Value::Bool(true),
- Type::String => Value::String(Rc::new("".to_string())),
- Type::Function(_, _) => Value::Function(
- Vec::new(),
- Rc::new(RefCell::new(Block::from_type(self)))),
}
}
-}
-pub type RustFunction = fn(&[Value], bool) -> Result<Value, ErrorKind>;
+ test_multiple!(
+ order_of_operations,
+ terms_and_factors: "1 + 1 * 2 <=> 3
+ 1 * 2 + 3 <=> 5",
+ in_rhs: "5 <=> 1 * 2 + 3",
+ parenthesis: "(1 + 2) * 3 <=> 9",
+ negation: "-1 <=> 0 - 1
+ -1 + 2 <=> 1
+ -(1 + 2) <=> -3
+ 1 + -1 <=> 0
+ 2 * -1 <=> -2",
+ );
-#[derive(Debug, Clone)]
-pub struct Blob {
- pub name: String,
+ test_multiple!(
+ variables,
+ single_variable: "a := 1
+ a <=> 1",
+ two_variables: "a := 1
+ b := 2
+ a <=> 1
+ b <=> 2",
+ stack_ordering: "a := 1
+ b := 2
+ b <=> 2
+ a <=> 1",
+ assignment: "a := 1
+ b := 2
+ a = b
+ a <=> 2
+ b <=> 2",
+ );
- pub name_to_field: HashMap<String, (usize, Type)>,
-}
+ test_multiple!(
+ if_,
+ compare_constants_equality: "if 1 == 2 {
+ <!>
+ }",
+ compare_constants_unequality: "if 1 != 1 {
+ <!>
+ }",
+ compare_variable: "a := 1
+ if a == 0 {
+ <!>
+ }
+ if a != 1 {
+ <!>
+ }",
+ else_: "a := 1
+ res := 0
+ if a == 0 {
+ <!>
+ } else {
+ res = 1
+ }
+ res <=> 1",
+ else_if: "a := 1
+ res := 0
+ if a == 0 {
+ <!>
+ } else if a == 1 {
+ res = 1
+ } else {
+ <!>
+ }
+ res <=> 1",
+ );
-impl Blob {
- pub fn new(name: &str) -> Self {
- Self {
- name: String::from(name),
- name_to_field: HashMap::new(),
- }
- }
+ test_multiple!(
+ fun,
+ simplest: "f := fn {}
+ f()",
+ param_1: "f := fn a: int {}
+ f(1)",
+ return_1: "f := fn -> int {
+ ret 1
+ }
+ f() <=> 1",
+ param_and_return: "f := fn a: int -> int {
+ ret a * 2
+ }
+ f(1) <=> 2
+ f(5) <=> 10",
+ param_2: "add := fn a: int, b: int -> int {
+ ret a + b
+ }
+ add(1, 1) <=> 2
+ add(10, 20) <=> 30",
+ calls_inside_calls: "one := fn -> int {
+ ret 1
+ }
+ add := fn a: int, b: int -> int {
+ ret a + b
+ }
+ add(one(), one()) <=> 2
+ add(add(one(), one()), one()) <=> 3
+ add(one(), add(one(), one())) <=> 3",
+ passing_functions: "g := fn -> int {
+ ret 1
+ }
+ f := fn inner: fn -> int -> int {
+ ret inner()
+ }
+ f(g) <=> 1",
+ passing_functions_mixed: "g := fn a: int -> int {
+ ret a * 2
+ }
+ f := fn inner: fn int -> int, a: int -> int {
+ ret inner(a)
+ }
+ f(g, 2) <=> 4",
+ multiple_returns: "f := fn a: int -> int {
+ if a == 1 {
+ ret 2
+ } else {
+ ret 3
+ }
+ }
+ f(0) <=> 3
+ f(1) <=> 2
+ f(2) <=> 3",
+ precedence: "f := fn a: int, b: int -> int {
+ ret a + b
+ }
+ 1 + f(2, 3) <=> 6
+ 2 * f(2, 3) <=> 10
+ f(2, 3) - (2 + 3) <=> 0",
+ factorial: "factorial : fn int -> int = fn n: int -> int {
+ if n <= 1 {
+ ret 1
+ }
+ ret n * factorial(n - 1)
+ }
+ factorial(5) <=> 120
+ factorial(6) <=> 720
+ factorial(12) <=> 479001600",
- pub fn add_field(&mut self, name: &str, ty: Type) -> Result<(), ()> {
- let size = self.name_to_field.len();
- let entry = self.name_to_field.entry(String::from(name));
- if matches!(entry, Entry::Occupied(_)) {
- Err(())
- } else {
- entry.or_insert((size, ty));
- Ok(())
- }
+ returning_closures: "
+f : fn -> fn -> int = fn -> fn -> int {
+ x : int = 0
+ f := fn -> int {
+ x = x + 1
+ ret x
}
+ f() <=> 1
+ ret f
+}
+
+a := f()
+b := f()
+
+a() <=> 2
+a() <=> 3
+
+b() <=> 2
+b() <=> 3
+
+a() <=> 4
+"
+
+ //TODO this tests doesn't terminate in proper time if we print blocks and ops
+ /*
+ fibonacci: "fibonacci : fn int -> int = fn n: int -> int {
+ if n == 0 {
+ ret 0
+ } else if n == 1 {
+ ret 1
+ } else if n < 0 {
+ <!>
+ }
+ ret fibonacci(n - 1) + fibonacci(n - 2)
+ }
+ fibonacci(10) <=> 55
+ fibonacci(20) <=> 6765"
+ */
+ );
+
+ test_multiple!(
+ blob,
+ simple: "blob A {}",
+ instantiate: "blob A {}
+ a := A()",
+ field: "blob A { a: int }",
+ field_assign: "blob A { a: int }
+ a := A()
+ a.a = 2",
+ field_get: "blob A { a: int }
+ a := A()
+ a.a = 2
+ a.a <=> 2
+ 2 <=> a.a",
+ multiple_fields: "blob A {
+ a: int
+ b: int
+ }
+ a := A()
+ a.a = 2
+ a.b = 3
+ a.a + a.b <=> 5
+ 5 <=> a.a + a.b"
+ );
+
+ test_multiple!(tuples,
+ add: "(1, 2, 3, 4) + (4, 3, 2, 1) <=> (5, 5, 5, 5)",
+ sub: "(1, -2, 3, -4) - (4, 3, -2, -1) <=> (-3, 1, 1, -5)",
+ mul: "(0, 1, 2) * (2, 3, 4) <=> (0, 3, 8)",
+ types: "a: (int, float, int) = (1, 1., 1)",
+ more_types: "a: (str, bool, int) = (\"abc\", true, 1)",
+ );
+
+ test_file!(scoping, "progs/tests/scoping.sy");
+ test_file!(for_, "progs/tests/for.sy");
+
+ test_multiple!(
+ op_assign,
+ add: "a := 1\na += 1\na <=> 2",
+ sub: "a := 2\na -= 1\na <=> 1",
+ mul: "a := 2\na *= 2\na <=> 4",
+ div: "a := 2\na /= 2\na <=> 1",
+ cluster: "
+blob A { a: int }
+a := A()
+a.a = 0
+a.a += 1
+a.a <=> 1
+a.a *= 2
+a.a <=> 2
+a.a /= 2
+a.a <=> 1
+a.a -= 1
+a.a <=> 0"
+ );
}