diff --git a/schala-lang/src/ast/mod.rs b/schala-lang/src/ast/mod.rs index 34e7d5d..6500ae5 100644 --- a/schala-lang/src/ast/mod.rs +++ b/schala-lang/src/ast/mod.rs @@ -202,8 +202,7 @@ pub struct TypeSingletonName { pub enum ExpressionKind { NatLiteral(u64), FloatLiteral(f64), - //TODO StringLiteral variant needs to support prefixes - StringLiteral(Rc), + StringLiteral { prefix: Option>, s: Rc }, BoolLiteral(bool), BinExp(BinOp, Box, Box), PrefixExp(PrefixOp, Box), diff --git a/schala-lang/src/ast/visitor.rs b/schala-lang/src/ast/visitor.rs index 3ca88c9..ca6e5e5 100644 --- a/schala-lang/src/ast/visitor.rs +++ b/schala-lang/src/ast/visitor.rs @@ -71,7 +71,7 @@ pub fn walk_expression(v: &mut V, expr: &Expression) { if let Recursion::Continue = v.expression(expr) { match &expr.kind { - NatLiteral(_) | FloatLiteral(_) | StringLiteral(_) | BoolLiteral(_) | Value(_) => (), + NatLiteral(_) | FloatLiteral(_) | StringLiteral { .. } | BoolLiteral(_) | Value(_) => (), BinExp(_, lhs, rhs) => { walk_expression(v, lhs); walk_expression(v, rhs); diff --git a/schala-lang/src/ast/visualize.rs b/schala-lang/src/ast/visualize.rs index 7eac88b..e9bca2f 100644 --- a/schala-lang/src/ast/visualize.rs +++ b/schala-lang/src/ast/visualize.rs @@ -47,7 +47,7 @@ fn render_expression(expr: &Expression, indent: usize, buf: &mut String) { match &expr.kind { NatLiteral(n) => buf.push_str(&format!("(NatLiteral {})", n)), FloatLiteral(f) => buf.push_str(&format!("(FloatLiteral {})", f)), - StringLiteral(s) => buf.push_str(&format!("(StringLiteral {})", s)), + StringLiteral { s, prefix } => buf.push_str(&format!("(StringLiteral prefix: {:?} {})", prefix, s)), BoolLiteral(b) => buf.push_str(&format!("(BoolLiteral {})", b)), BinExp(binop, lhs, rhs) => { let new_indent = indent + LEVEL; diff --git a/schala-lang/src/parsing/combinator.rs b/schala-lang/src/parsing/combinator.rs index 872f9e6..4a59f75 100644 --- a/schala-lang/src/parsing/combinator.rs +++ b/schala-lang/src/parsing/combinator.rs @@ -830,11 +830,14 @@ fn list_expr(input: Span) -> ParseResult { })(input) } -//TODO need to do something with prefix in the AST fn string_literal(input: Span) -> ParseResult { - tok(map(pair(opt(identifier), bare_string_literal), |(_maybe_prefix, s)| { - ExpressionKind::StringLiteral(Rc::new(s)) - }))(input) + context( + "string-literal", + tok(map(pair(opt(identifier), bare_string_literal), |(prefix, s)| ExpressionKind::StringLiteral { + s: Rc::new(s), + prefix: prefix.map(|s| rc_string(s.fragment())), + })), + )(input) } fn bare_string_literal(input: Span) -> ParseResult { diff --git a/schala-lang/src/parsing/peg_parser.rs b/schala-lang/src/parsing/peg_parser.rs index c54386b..af8ea73 100644 --- a/schala-lang/src/parsing/peg_parser.rs +++ b/schala-lang/src/parsing/peg_parser.rs @@ -446,9 +446,10 @@ peg::parser! { } } - //TODO need to do something with prefix in the AST rule string_literal() -> ExpressionKind = - prefix:identifier()? s:bare_string_literal(){ ExpressionKind::StringLiteral(Rc::new(s.to_string())) } + prefix:identifier()? s:bare_string_literal(){ ExpressionKind::StringLiteral{ s: Rc::new(s.to_string()), + prefix: prefix.map(rc_string) + } } rule bare_string_literal() -> &'input str = "\"" s:$(string_component()*) "\"" { s } diff --git a/schala-lang/src/parsing/test.rs b/schala-lang/src/parsing/test.rs index 8947e46..95fae54 100644 --- a/schala-lang/src/parsing/test.rs +++ b/schala-lang/src/parsing/test.rs @@ -17,6 +17,10 @@ fn bx(item: T) -> Box { Box::new(item) } +fn strlit(s: &str) -> ExpressionKind { + ExpressionKind::StringLiteral { s: Rc::new(s.to_string()), prefix: None } +} + fn stmt(kind: StatementKind) -> Statement { Statement { location: Location::default(), id: ItemId::default(), kind } } @@ -179,9 +183,12 @@ fn basic_literals() { fn string_literals() { use ExpressionKind::*; - assert_expr!(r#""""#, expr(StringLiteral(rc("")))); - assert_expr!(r#""hello""#, expr(StringLiteral(rc("hello")))); - assert_expr!(r#"b"some bytestring""#, expr(StringLiteral(rc("some bytestring")))); + assert_expr!(r#""""#, expr(strlit(""))); + assert_expr!(r#""hello""#, expr(strlit("hello"))); + assert_expr!( + r#"b"some bytestring""#, + expr(StringLiteral { s: rc("some bytestring"), prefix: Some(rc("b")) }) + ); //NOTE I'm not 100% sure this case is correct, but I'll deal with it later //assert_expr!(r#""Do \n \" escapes work\t""#, expr(StringLiteral(rc("Do \n \" escapes work\t")))); } @@ -296,15 +303,12 @@ fn tuples() { use ExpressionKind::*; assert_expr!("()", expr(TupleLiteral(vec![]))); - assert_expr!( - r#"("hella", 34)"#, - expr(TupleLiteral(vec![expr(StringLiteral(rc("hella"))), expr(NatLiteral(34))])) - ); + assert_expr!(r#"("hella", 34)"#, expr(TupleLiteral(vec![expr(strlit("hella")), expr(NatLiteral(34))]))); assert_expr!( r#"(1+2, "slough")"#, expr(TupleLiteral(vec![ binop("+", expr(NatLiteral(1)), expr(NatLiteral(2))), - expr(StringLiteral(rc("slough"))), + expr(strlit("slough")), ])) ); } @@ -473,7 +477,7 @@ fn lambda_expressions() { name: rc("String"), params: vec![] })), - body: vec![stmt(StatementKind::Expression(expr(StringLiteral(rc("q"))))),].into() + body: vec![stmt(StatementKind::Expression(expr(strlit("q")))),].into() }) ); } @@ -552,9 +556,8 @@ fn complex_lambdas() { #[test] fn reserved_words() { - let err = "0: at line 1, in Verify:\nmodule::item::call()\n^\n\n1: at line 1, in token:\nmodule::item::call()\n^\n\n2: at line 1, in identifier:\nmodule::item::call()\n^\n\n3: at line 1, in token:\nmodule::item::call()\n^\n\n4: at line 1, in primary-expr-no-struct:\nmodule::item::call()\n^\n\n5: at line 1, in primary-expr:\nmodule::item::call()\n^\n\n6: at line 1, in extended-expr:\nmodule::item::call()\n^\n\n7: at line 1, in prefix-expr:\nmodule::item::call()\n^\n\n8: at line 1, in expression-kind:\nmodule::item::call()\n^\n\n9: at line 1, in Parsing-statement:\nmodule::item::call()\n^\n\n10: at line 1, in AST:\nmodule::item::call()\n^\n\n"; - assert_fail!("module::item::call()", err); - + //TODO assert a good error message for this + assert_fail!("module::item::call()"); assert_expr!("modulek::item", expr(ExpressionKind::Value(qn!(modulek, item)))); } @@ -1278,7 +1281,7 @@ if (45, "panda", false, 2.2) { expr( IfExpression { discriminator: Some(bx(expr(TupleLiteral(vec![ - expr(NatLiteral(45)), expr(StringLiteral(rc("panda"))), expr(BoolLiteral(false)), expr(FloatLiteral(2.2)) + expr(NatLiteral(45)), expr(strlit("panda")), expr(BoolLiteral(false)), expr(FloatLiteral(2.2)) ])))), body: bx(IfExpressionBody::CondList(vec![ ConditionArm { @@ -1291,7 +1294,7 @@ if (45, "panda", false, 2.2) { ] )), guard: None, - body: vec![stmt(StatementKind::Expression(expr(StringLiteral(rc("no")))))].into(), + body: vec![stmt(StatementKind::Expression(expr(strlit("no"))))].into(), }, ConditionArm { condition: Condition::Pattern(Pattern::TuplePattern( @@ -1303,12 +1306,12 @@ if (45, "panda", false, 2.2) { ] )), guard: None, - body: vec![stmt(StatementKind::Expression(expr(StringLiteral(rc("yes")))))].into(), + body: vec![stmt(StatementKind::Expression(expr(strlit("yes"))))].into(), }, ConditionArm { condition: Condition::Pattern(Pattern::Ignored), guard: None, - body: vec![exst(StringLiteral(rc("maybe")))].into(), + body: vec![exst(strlit("maybe"))].into(), }, ])) } diff --git a/schala-lang/src/reduced_ir/mod.rs b/schala-lang/src/reduced_ir/mod.rs index 06cb705..182d55f 100644 --- a/schala-lang/src/reduced_ir/mod.rs +++ b/schala-lang/src/reduced_ir/mod.rs @@ -126,7 +126,8 @@ impl<'a, 'b> Reducer<'a, 'b> { match &expr.kind { NatLiteral(n) => Expression::Literal(Literal::Nat(*n)), FloatLiteral(f) => Expression::Literal(Literal::Float(*f)), - StringLiteral(s) => Expression::Literal(Literal::StringLit(s.clone())), + //TODO implement handling string literal prefixes + StringLiteral { s, prefix: _ } => Expression::Literal(Literal::StringLit(s.clone())), BoolLiteral(b) => Expression::Literal(Literal::Bool(*b)), BinExp(binop, lhs, rhs) => self.binop(binop, lhs, rhs), PrefixExp(op, arg) => self.prefix(op, arg),