mirror of
https://github.com/azur1s/bobbylisp.git
synced 2024-10-16 02:37:40 -05:00
parsed function as argument
This commit is contained in:
parent
6d41cc4ded
commit
c095efdd7c
|
@ -1,5 +1,5 @@
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use parser::Expr;
|
use parser::types::{Expr, Typehint};
|
||||||
|
|
||||||
const INTRINSICS: [&str; 8] = [
|
const INTRINSICS: [&str; 8] = [
|
||||||
"write",
|
"write",
|
||||||
|
@ -30,6 +30,7 @@ impl std::fmt::Display for Value {
|
||||||
pub enum IRKind {
|
pub enum IRKind {
|
||||||
Value { value: Value },
|
Value { value: Value },
|
||||||
Vector { values: Vec<Self> },
|
Vector { values: Vec<Self> },
|
||||||
|
Tuple { values: Vec<Self> },
|
||||||
|
|
||||||
Unary {
|
Unary {
|
||||||
op: String,
|
op: String,
|
||||||
|
@ -422,7 +423,7 @@ pub fn expr_to_ir(expr: &Expr) -> (Option<IRKind>, Option<LoweringError>) {
|
||||||
Expr::String(value) => return_ok!(IRKind::Value { value: Value::String(value.clone()) }),
|
Expr::String(value) => return_ok!(IRKind::Value { value: Value::String(value.clone()) }),
|
||||||
Expr::Identifier(value) => return_ok!(IRKind::Value { value: Value::Ident(value.clone()) }),
|
Expr::Identifier(value) => return_ok!(IRKind::Value { value: Value::Ident(value.clone()) }),
|
||||||
|
|
||||||
Expr::Vector(values) => {
|
v @ Expr::Vector(values) | v @ Expr::Tuple(values) => {
|
||||||
let mut lvalues = Vec::new();
|
let mut lvalues = Vec::new();
|
||||||
for value in values {
|
for value in values {
|
||||||
let value = expr_to_ir(&value.0);
|
let value = expr_to_ir(&value.0);
|
||||||
|
@ -430,7 +431,11 @@ pub fn expr_to_ir(expr: &Expr) -> (Option<IRKind>, Option<LoweringError>) {
|
||||||
|
|
||||||
lvalues.push(value.0.unwrap());
|
lvalues.push(value.0.unwrap());
|
||||||
}
|
}
|
||||||
(Some(IRKind::Vector { values: lvalues }), None)
|
match v {
|
||||||
|
Expr::Vector(..) => return_ok!(IRKind::Vector { values: lvalues }),
|
||||||
|
Expr::Tuple(..) => return_ok!(IRKind::Tuple { values: lvalues }),
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Probably will never happen because it is catched in parser
|
// Probably will never happen because it is catched in parser
|
||||||
|
@ -442,16 +447,21 @@ pub fn expr_to_ir(expr: &Expr) -> (Option<IRKind>, Option<LoweringError>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_type_hint(type_hint: &str) -> String {
|
fn gen_type_hint(type_hint: &Typehint) -> String {
|
||||||
match type_hint {
|
match type_hint {
|
||||||
|
Typehint::Single(t) => match t.as_str() {
|
||||||
"int" => "number".to_string(),
|
"int" => "number".to_string(),
|
||||||
"bool" => "boolean".to_string(),
|
"bool" => "boolean".to_string(),
|
||||||
"string" => "string".to_string(),
|
_ => t.to_string()
|
||||||
"void" => "void".to_string(),
|
},
|
||||||
// TODO: Un-hardcode types
|
Typehint::Tuple(ts) => {
|
||||||
"vec_int" => "number[]".to_string(),
|
let mut types = Vec::new();
|
||||||
"vec_bool" => "boolean[]".to_string(),
|
for t in ts {
|
||||||
"vec_string" => "string[]".to_string(),
|
types.push(gen_type_hint(&t.0));
|
||||||
_ => { dbg!(type_hint); todo!() }
|
}
|
||||||
|
format!("[{}]", types.join(", "))
|
||||||
|
},
|
||||||
|
Typehint::Vector(t) => format!("{}[]", gen_type_hint(&t.0)),
|
||||||
|
Typehint::Function(_args, _ret) => {dbg!(type_hint); todo!()}, // TODO: Function type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,24 +170,3 @@ pub fn lex(src: String) -> (Option<Vec<(Token, std::ops::Range<usize>)>>, Vec<Si
|
||||||
let (tokens, lex_error) = lexer().parse_recovery(src.as_str());
|
let (tokens, lex_error) = lexer().parse_recovery(src.as_str());
|
||||||
(tokens, lex_error)
|
(tokens, lex_error)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn lex_let_simple() {
|
|
||||||
let (tokens, err) = lex("let x: Int = 1;".to_string());
|
|
||||||
|
|
||||||
assert_eq!(tokens, Some(vec![
|
|
||||||
(Token::KwLet, 0..3),
|
|
||||||
(Token::Identifier("x".to_string()), 4..5),
|
|
||||||
(Token::Colon, 5..6),
|
|
||||||
(Token::Identifier("Int".to_string()), 7..10),
|
|
||||||
(Token::Assign, 11..12),
|
|
||||||
(Token::Int(1), 13..14),
|
|
||||||
(Token::SemiColon, 14..15),
|
|
||||||
]));
|
|
||||||
assert_eq!(err, vec![]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,53 +1,53 @@
|
||||||
use chumsky::{prelude::*, Stream};
|
use chumsky::{prelude::*, Stream};
|
||||||
use lexer::Token;
|
use lexer::Token;
|
||||||
|
|
||||||
pub type Spanned<T> = (T, std::ops::Range<usize>);
|
pub mod types;
|
||||||
|
use types::{Expr, Spanned, Typehint};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
fn typehint_parser() -> impl Parser<Token, Spanned<Typehint>, Error = Simple<Token>> + Clone {
|
||||||
pub enum Expr {
|
let single = filter_map(|span, token| match token {
|
||||||
Int(i64), Float(f64), Boolean(bool),
|
Token::Identifier(s) => Ok((Typehint::Single(s), span)),
|
||||||
String(String), Identifier(String),
|
_ => Err(Simple::expected_input_found(span, Vec::new(), Some(token))),
|
||||||
|
});
|
||||||
|
|
||||||
Vector(Vec<Spanned<Self>>),
|
let tuple = single
|
||||||
|
.separated_by(just(Token::Comma))
|
||||||
|
.allow_trailing()
|
||||||
|
.delimited_by(
|
||||||
|
just(Token::OpenParen),
|
||||||
|
just(Token::CloseParen),
|
||||||
|
)
|
||||||
|
.map_with_span(|args, span| {
|
||||||
|
(Typehint::Tuple(args), span)
|
||||||
|
});
|
||||||
|
|
||||||
Unary { op: String, rhs: Box<Spanned<Self>> },
|
let vector = single
|
||||||
Binary { lhs: Box<Spanned<Self>>, op: String, rhs: Box<Spanned<Self>> },
|
.delimited_by(
|
||||||
Call { name: Box<Spanned<Self>>, args: Spanned<Vec<Spanned<Self>>> },
|
just(Token::OpenBracket),
|
||||||
Pipeline { lhs: Box<Spanned<Self>>, rhs: Box<Spanned<Self>> },
|
just(Token::CloseBracket),
|
||||||
Intrinsic { name: Box<Spanned<Self>>, args: Spanned<Vec<Spanned<Self>>> },
|
)
|
||||||
|
.map_with_span(|arg, span| {
|
||||||
|
(Typehint::Vector(Box::new(arg)), span)
|
||||||
|
});
|
||||||
|
|
||||||
Let {
|
let function = single
|
||||||
public: bool,
|
.separated_by(just(Token::Comma))
|
||||||
name: Spanned<String>,
|
.allow_trailing()
|
||||||
type_hint: Spanned<String>,
|
.delimited_by(
|
||||||
value: Box<Spanned<Self>>,
|
just(Token::Pipe),
|
||||||
mutable: bool,
|
just(Token::Pipe),
|
||||||
},
|
)
|
||||||
Fun {
|
.then_ignore(just(Token::Arrow))
|
||||||
public: bool,
|
.then(single)
|
||||||
name: Spanned<String>,
|
.map_with_span(|(args, ret), span| {
|
||||||
type_hint: Spanned<String>,
|
(Typehint::Function(args, Box::new(ret)), span)
|
||||||
args: Spanned<Vec<(Spanned<String>, Spanned<String>)>>,
|
});
|
||||||
body: Box<Spanned<Self>>
|
|
||||||
},
|
|
||||||
Return { expr: Box<Spanned<Self>> },
|
|
||||||
|
|
||||||
If {
|
single
|
||||||
cond: Box<Spanned<Self>>,
|
.or(tuple)
|
||||||
body: Box<Spanned<Self>>,
|
.or(vector)
|
||||||
else_body: Box<Spanned<Self>>
|
.or(function)
|
||||||
},
|
.labelled("type hint")
|
||||||
Case {
|
|
||||||
expr: Box<Spanned<Self>>,
|
|
||||||
cases: Spanned<Vec<(Spanned<Self>, Spanned<Self>)>>,
|
|
||||||
default: Box<Spanned<Self>>
|
|
||||||
},
|
|
||||||
Do {
|
|
||||||
body: Spanned<Vec<Spanned<Self>>>
|
|
||||||
},
|
|
||||||
|
|
||||||
// Hole for positional argument(s) in piping
|
|
||||||
Hole(usize, usize), // The usize is the span of the hole (prob should be single but whatever)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr_parser() -> impl Parser<Token, Vec<Spanned<Expr>>, Error = Simple<Token>> + Clone {
|
fn expr_parser() -> impl Parser<Token, Vec<Spanned<Expr>>, Error = Simple<Token>> + Clone {
|
||||||
|
@ -83,9 +83,24 @@ fn expr_parser() -> impl Parser<Token, Vec<Spanned<Expr>>, Error = Simple<Token>
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let tuple = expr.clone()
|
||||||
|
.separated_by(just(Token::Comma))
|
||||||
|
.allow_trailing()
|
||||||
|
.delimited_by(
|
||||||
|
just(Token::OpenParen),
|
||||||
|
just(Token::CloseParen),
|
||||||
|
)
|
||||||
|
.map_with_span(|args, span| {
|
||||||
|
(
|
||||||
|
Expr::Tuple(args),
|
||||||
|
span,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
let atom = literal
|
let atom = literal
|
||||||
.or(identifier.map(|(s, span)| (Expr::Identifier(s), span)))
|
.or(identifier.map(|(s, span)| (Expr::Identifier(s), span)))
|
||||||
.or(vector)
|
.or(vector)
|
||||||
|
.or(tuple)
|
||||||
.labelled("atom");
|
.labelled("atom");
|
||||||
|
|
||||||
let call = atom.clone()
|
let call = atom.clone()
|
||||||
|
@ -219,7 +234,7 @@ fn expr_parser() -> impl Parser<Token, Vec<Spanned<Expr>>, Error = Simple<Token>
|
||||||
.then(just(Token::KwMut).or_not())
|
.then(just(Token::KwMut).or_not())
|
||||||
.then(identifier)
|
.then(identifier)
|
||||||
.then_ignore(just(Token::Colon))
|
.then_ignore(just(Token::Colon))
|
||||||
.then(identifier)
|
.then(typehint_parser())
|
||||||
.then_ignore(just(Token::Assign))
|
.then_ignore(just(Token::Assign))
|
||||||
.then(expr.clone())
|
.then(expr.clone())
|
||||||
.map(|((((public, mutable), name), type_hint), value)| {
|
.map(|((((public, mutable), name), type_hint), value)| {
|
||||||
|
@ -241,7 +256,7 @@ fn expr_parser() -> impl Parser<Token, Vec<Spanned<Expr>>, Error = Simple<Token>
|
||||||
.then(
|
.then(
|
||||||
identifier
|
identifier
|
||||||
.then_ignore(just(Token::Colon))
|
.then_ignore(just(Token::Colon))
|
||||||
.then(identifier)
|
.then(typehint_parser())
|
||||||
.delimited_by(
|
.delimited_by(
|
||||||
just(Token::OpenParen),
|
just(Token::OpenParen),
|
||||||
just(Token::CloseParen),
|
just(Token::CloseParen),
|
||||||
|
@ -249,7 +264,7 @@ fn expr_parser() -> impl Parser<Token, Vec<Spanned<Expr>>, Error = Simple<Token>
|
||||||
.repeated()
|
.repeated()
|
||||||
)
|
)
|
||||||
.then_ignore(just(Token::Colon))
|
.then_ignore(just(Token::Colon))
|
||||||
.then(identifier)
|
.then(typehint_parser())
|
||||||
.then_ignore(just(Token::Assign))
|
.then_ignore(just(Token::Assign))
|
||||||
.then(expr.clone())
|
.then(expr.clone())
|
||||||
.map(|((((public, name), args), type_hint), body)| {
|
.map(|((((public, name), args), type_hint), body)| {
|
||||||
|
@ -371,22 +386,3 @@ pub fn parse(tokens: Vec<(Token, std::ops::Range<usize>)>, len: usize) -> (Optio
|
||||||
|
|
||||||
(ast, parse_error)
|
(ast, parse_error)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parse_simple() {
|
|
||||||
let (_, err) = parse(vec![
|
|
||||||
(Token::KwLet, 0..3),
|
|
||||||
(Token::Identifier("x".to_string()), 4..5),
|
|
||||||
(Token::Colon, 5..6),
|
|
||||||
(Token::Identifier("Int".to_string()), 7..10),
|
|
||||||
(Token::Assign, 11..12),
|
|
||||||
(Token::Int(1), 13..14),
|
|
||||||
], 15);
|
|
||||||
|
|
||||||
assert_eq!(err, vec![]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
58
crates/parser/src/types.rs
Normal file
58
crates/parser/src/types.rs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
|
||||||
|
pub type Spanned<T> = (T, std::ops::Range<usize>);
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum Typehint {
|
||||||
|
Single(String), // e.g. `int`, `bool`, `string`
|
||||||
|
Tuple(Vec<Spanned<Self>>), // e.g. `(int, bool)`
|
||||||
|
Vector(Box<Spanned<Self>>), // e.g. `[int]`
|
||||||
|
Function(Vec<Spanned<Self>>, Box<Spanned<Self>>), // e.g. `(a: int, b: bool) -> string`, `(b: int) -> [bool]`
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum Expr {
|
||||||
|
Int(i64), Float(f64), Boolean(bool),
|
||||||
|
String(String), Identifier(String),
|
||||||
|
|
||||||
|
Tuple(Vec<Spanned<Self>>), // Wait, its all Vec<Spanned<Self>>?
|
||||||
|
Vector(Vec<Spanned<Self>>), // Always have been
|
||||||
|
|
||||||
|
Unary { op: String, rhs: Box<Spanned<Self>> },
|
||||||
|
Binary { lhs: Box<Spanned<Self>>, op: String, rhs: Box<Spanned<Self>> },
|
||||||
|
Call { name: Box<Spanned<Self>>, args: Spanned<Vec<Spanned<Self>>> },
|
||||||
|
Pipeline { lhs: Box<Spanned<Self>>, rhs: Box<Spanned<Self>> },
|
||||||
|
Intrinsic { name: Box<Spanned<Self>>, args: Spanned<Vec<Spanned<Self>>> },
|
||||||
|
|
||||||
|
Let {
|
||||||
|
public: bool,
|
||||||
|
name: Spanned<String>,
|
||||||
|
type_hint: Spanned<Typehint>,
|
||||||
|
value: Box<Spanned<Self>>,
|
||||||
|
mutable: bool,
|
||||||
|
},
|
||||||
|
Fun {
|
||||||
|
public: bool,
|
||||||
|
name: Spanned<String>,
|
||||||
|
type_hint: Spanned<Typehint>,
|
||||||
|
args: Spanned<Vec<(Spanned<String>, Spanned<Typehint>)>>,
|
||||||
|
body: Box<Spanned<Self>>
|
||||||
|
},
|
||||||
|
Return { expr: Box<Spanned<Self>> },
|
||||||
|
|
||||||
|
If {
|
||||||
|
cond: Box<Spanned<Self>>,
|
||||||
|
body: Box<Spanned<Self>>,
|
||||||
|
else_body: Box<Spanned<Self>>
|
||||||
|
},
|
||||||
|
Case {
|
||||||
|
expr: Box<Spanned<Self>>,
|
||||||
|
cases: Spanned<Vec<(Spanned<Self>, Spanned<Self>)>>,
|
||||||
|
default: Box<Spanned<Self>>
|
||||||
|
},
|
||||||
|
Do {
|
||||||
|
body: Spanned<Vec<Spanned<Self>>>
|
||||||
|
},
|
||||||
|
|
||||||
|
// Hole for positional argument(s) in piping
|
||||||
|
Hole(usize, usize), // The usize is the span of the hole (prob should be single but whatever)
|
||||||
|
}
|
|
@ -1,3 +0,0 @@
|
||||||
let foo: int = "123"
|
|
||||||
let bar: string = 69
|
|
||||||
let baz: bool = "true"
|
|
|
@ -1,7 +0,0 @@
|
||||||
fun main: void = do
|
|
||||||
do
|
|
||||||
let foo: string = "Hello"
|
|
||||||
@write(foo)
|
|
||||||
end
|
|
||||||
@write(foo) -- TODO: This is a runtime error
|
|
||||||
end
|
|
|
@ -1,3 +0,0 @@
|
||||||
fun main: void = do
|
|
||||||
@throw("woopsie")
|
|
||||||
end
|
|
|
@ -1,3 +0,0 @@
|
||||||
fun main: void = do
|
|
||||||
@writse() -- Unknown intrinsic
|
|
||||||
end
|
|
|
@ -1,3 +0,0 @@
|
||||||
pub fun print_something: void = @emit("console.log('something')")
|
|
||||||
|
|
||||||
fun main: void = do end
|
|
|
@ -1,15 +0,0 @@
|
||||||
fun main: void = do
|
|
||||||
if true then
|
|
||||||
@write("True")
|
|
||||||
else
|
|
||||||
@write("False")
|
|
||||||
end
|
|
||||||
|
|
||||||
if true then
|
|
||||||
do
|
|
||||||
@write("True")
|
|
||||||
end
|
|
||||||
else
|
|
||||||
@write("False")
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,12 +0,0 @@
|
||||||
fun main: void = do
|
|
||||||
let foo: int = 3
|
|
||||||
|
|
||||||
match foo with
|
|
||||||
| 1 -> @write("One")
|
|
||||||
| 2 -> @write("Two")
|
|
||||||
| 3 -> do
|
|
||||||
@write("Three")
|
|
||||||
end
|
|
||||||
| else @write("idk")
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,14 +0,0 @@
|
||||||
fun foo (xs: int): int = return xs + 1
|
|
||||||
fun bar (xs: int) (x: int): int = return xs - x
|
|
||||||
|
|
||||||
fun main: void = do
|
|
||||||
foo(69) -- 69 + 1 => 70
|
|
||||||
|> bar(_, 1) -- '70 - 1 => 69
|
|
||||||
|> @write(_) -- '69 => stdout
|
|
||||||
|
|
||||||
@write("\n")
|
|
||||||
|
|
||||||
foo(60) -- 60 + 1 => 61
|
|
||||||
|> bar(130, _) -- 130 - '61 => 69
|
|
||||||
|> @write(_) -- '69 => stdout
|
|
||||||
end
|
|
|
@ -1,19 +0,0 @@
|
||||||
fun foo (xs: int) : int = return xs + 1
|
|
||||||
fun bar (xs: int) (ys: int) : int = return xs + ys
|
|
||||||
fun baz (xs: int) (ys: int) (zs: int): int = return xs + ys + zs
|
|
||||||
fun qux (xs: int) : int = return xs - 1
|
|
||||||
fun quux (xs: int) (xy: int) : int = return xs - 2 + xy
|
|
||||||
|
|
||||||
fun main: void = do
|
|
||||||
66
|
|
||||||
|> foo(_)
|
|
||||||
|> bar(_, 1)
|
|
||||||
|> baz(1, 2, _)
|
|
||||||
|> qux(_)
|
|
||||||
|> quux(1, _)
|
|
||||||
|> @write(_)
|
|
||||||
|
|
||||||
210
|
|
||||||
|> bar(_, _)
|
|
||||||
|> @write(_)
|
|
||||||
end
|
|
|
@ -1,16 +0,0 @@
|
||||||
fun main: void = do
|
|
||||||
let str: string = "Hello, World"
|
|
||||||
|
|
||||||
-- Matching string(s)
|
|
||||||
match str with
|
|
||||||
| "Hello, World" -> @write("yes\n")
|
|
||||||
| else @write("no\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Indexing character in string
|
|
||||||
let foo: string = @get(str, 0)
|
|
||||||
match foo with
|
|
||||||
| "H" -> @write("still yes")
|
|
||||||
| else @write("no H")
|
|
||||||
end
|
|
||||||
end
|
|
6
example/tuples.hz
Normal file
6
example/tuples.hz
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
fun test (foo: int) (bar: int) : int = foo * bar
|
||||||
|
fun f (fn: |int, int| -> int) (x: int) : int = fn(x)
|
||||||
|
|
||||||
|
fun main: void = do
|
||||||
|
let x : int = 20
|
||||||
|
end
|
Loading…
Reference in a new issue