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 parser::Expr;
|
||||
use parser::types::{Expr, Typehint};
|
||||
|
||||
const INTRINSICS: [&str; 8] = [
|
||||
"write",
|
||||
|
@ -30,6 +30,7 @@ impl std::fmt::Display for Value {
|
|||
pub enum IRKind {
|
||||
Value { value: Value },
|
||||
Vector { values: Vec<Self> },
|
||||
Tuple { values: Vec<Self> },
|
||||
|
||||
Unary {
|
||||
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::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();
|
||||
for value in values {
|
||||
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());
|
||||
}
|
||||
(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
|
||||
|
@ -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 {
|
||||
"int" => "number".to_string(),
|
||||
"bool" => "boolean".to_string(),
|
||||
"string" => "string".to_string(),
|
||||
"void" => "void".to_string(),
|
||||
// TODO: Un-hardcode types
|
||||
"vec_int" => "number[]".to_string(),
|
||||
"vec_bool" => "boolean[]".to_string(),
|
||||
"vec_string" => "string[]".to_string(),
|
||||
_ => { dbg!(type_hint); todo!() }
|
||||
Typehint::Single(t) => match t.as_str() {
|
||||
"int" => "number".to_string(),
|
||||
"bool" => "boolean".to_string(),
|
||||
_ => t.to_string()
|
||||
},
|
||||
Typehint::Tuple(ts) => {
|
||||
let mut types = Vec::new();
|
||||
for t in ts {
|
||||
types.push(gen_type_hint(&t.0));
|
||||
}
|
||||
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());
|
||||
(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 lexer::Token;
|
||||
|
||||
pub type Spanned<T> = (T, std::ops::Range<usize>);
|
||||
pub mod types;
|
||||
use types::{Expr, Spanned, Typehint};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Expr {
|
||||
Int(i64), Float(f64), Boolean(bool),
|
||||
String(String), Identifier(String),
|
||||
fn typehint_parser() -> impl Parser<Token, Spanned<Typehint>, Error = Simple<Token>> + Clone {
|
||||
let single = filter_map(|span, token| match token {
|
||||
Token::Identifier(s) => Ok((Typehint::Single(s), span)),
|
||||
_ => 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>> },
|
||||
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 vector = single
|
||||
.delimited_by(
|
||||
just(Token::OpenBracket),
|
||||
just(Token::CloseBracket),
|
||||
)
|
||||
.map_with_span(|arg, span| {
|
||||
(Typehint::Vector(Box::new(arg)), span)
|
||||
});
|
||||
|
||||
Let {
|
||||
public: bool,
|
||||
name: Spanned<String>,
|
||||
type_hint: Spanned<String>,
|
||||
value: Box<Spanned<Self>>,
|
||||
mutable: bool,
|
||||
},
|
||||
Fun {
|
||||
public: bool,
|
||||
name: Spanned<String>,
|
||||
type_hint: Spanned<String>,
|
||||
args: Spanned<Vec<(Spanned<String>, Spanned<String>)>>,
|
||||
body: Box<Spanned<Self>>
|
||||
},
|
||||
Return { expr: Box<Spanned<Self>> },
|
||||
let function = single
|
||||
.separated_by(just(Token::Comma))
|
||||
.allow_trailing()
|
||||
.delimited_by(
|
||||
just(Token::Pipe),
|
||||
just(Token::Pipe),
|
||||
)
|
||||
.then_ignore(just(Token::Arrow))
|
||||
.then(single)
|
||||
.map_with_span(|(args, ret), span| {
|
||||
(Typehint::Function(args, Box::new(ret)), span)
|
||||
});
|
||||
|
||||
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)
|
||||
single
|
||||
.or(tuple)
|
||||
.or(vector)
|
||||
.or(function)
|
||||
.labelled("type hint")
|
||||
}
|
||||
|
||||
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
|
||||
.or(identifier.map(|(s, span)| (Expr::Identifier(s), span)))
|
||||
.or(vector)
|
||||
.or(tuple)
|
||||
.labelled("atom");
|
||||
|
||||
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(identifier)
|
||||
.then_ignore(just(Token::Colon))
|
||||
.then(identifier)
|
||||
.then(typehint_parser())
|
||||
.then_ignore(just(Token::Assign))
|
||||
.then(expr.clone())
|
||||
.map(|((((public, mutable), name), type_hint), value)| {
|
||||
|
@ -241,7 +256,7 @@ fn expr_parser() -> impl Parser<Token, Vec<Spanned<Expr>>, Error = Simple<Token>
|
|||
.then(
|
||||
identifier
|
||||
.then_ignore(just(Token::Colon))
|
||||
.then(identifier)
|
||||
.then(typehint_parser())
|
||||
.delimited_by(
|
||||
just(Token::OpenParen),
|
||||
just(Token::CloseParen),
|
||||
|
@ -249,7 +264,7 @@ fn expr_parser() -> impl Parser<Token, Vec<Spanned<Expr>>, Error = Simple<Token>
|
|||
.repeated()
|
||||
)
|
||||
.then_ignore(just(Token::Colon))
|
||||
.then(identifier)
|
||||
.then(typehint_parser())
|
||||
.then_ignore(just(Token::Assign))
|
||||
.then(expr.clone())
|
||||
.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)
|
||||
}
|
||||
|
||||
#[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