diff options
author | Griffin Smith <root@gws.fyi> | 2021-03-14T15·53-0400 |
---|---|---|
committer | Griffin Smith <root@gws.fyi> | 2021-03-14T15·53-0400 |
commit | 39656a3801bb311edd9ebb65e92a24fc48f69ec7 (patch) | |
tree | d408937901c7789c033373019a94e014a03522a8 | |
parent | 32a5c0ff0fc58aa6721c1e0ad41950bde2d66744 (diff) |
Add string support to the frontend
-rw-r--r-- | src/ast/hir.rs | 4 | ||||
-rw-r--r-- | src/ast/mod.rs | 19 | ||||
-rw-r--r-- | src/codegen/llvm.rs | 1 | ||||
-rw-r--r-- | src/interpreter/mod.rs | 1 | ||||
-rw-r--r-- | src/interpreter/value.rs | 23 | ||||
-rw-r--r-- | src/main.rs | 2 | ||||
-rw-r--r-- | src/parser/expr.rs | 34 | ||||
-rw-r--r-- | src/parser/mod.rs | 12 | ||||
-rw-r--r-- | src/parser/type_.rs | 2 | ||||
-rw-r--r-- | src/tc/mod.rs | 8 |
10 files changed, 95 insertions, 11 deletions
diff --git a/src/ast/hir.rs b/src/ast/hir.rs index 151ddd529872..9db6919f6f53 100644 --- a/src/ast/hir.rs +++ b/src/ast/hir.rs @@ -26,7 +26,7 @@ impl<'a, T> Binding<'a, T> { pub enum Expr<'a, T> { Ident(Ident<'a>, T), - Literal(Literal, T), + Literal(Literal<'a>, T), UnaryOp { op: UnaryOperator, @@ -158,7 +158,7 @@ impl<'a, T> Expr<'a, T> { { match self { Expr::Ident(id, t) => Expr::Ident(id.to_owned(), t.clone()), - Expr::Literal(lit, t) => Expr::Literal(lit.clone(), t.clone()), + Expr::Literal(lit, t) => Expr::Literal(lit.to_owned(), t.clone()), Expr::UnaryOp { op, rhs, type_ } => Expr::UnaryOp { op: *op, rhs: Box::new((**rhs).to_owned()), diff --git a/src/ast/mod.rs b/src/ast/mod.rs index cef366d16e04..5526c5348350 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -107,9 +107,20 @@ pub enum UnaryOperator { } #[derive(Debug, PartialEq, Eq, Clone)] -pub enum Literal { +pub enum Literal<'a> { Int(u64), Bool(bool), + String(Cow<'a, str>), +} + +impl<'a> Literal<'a> { + pub fn to_owned(&self) -> Literal<'static> { + match self { + Literal::Int(i) => Literal::Int(*i), + Literal::Bool(b) => Literal::Bool(*b), + Literal::String(s) => Literal::String(Cow::Owned(s.clone().into_owned())), + } + } } #[derive(Debug, PartialEq, Eq, Clone)] @@ -133,7 +144,7 @@ impl<'a> Binding<'a> { pub enum Expr<'a> { Ident(Ident<'a>), - Literal(Literal), + Literal(Literal<'a>), UnaryOp { op: UnaryOperator, @@ -174,7 +185,7 @@ impl<'a> Expr<'a> { pub fn to_owned(&self) -> Expr<'static> { match self { Expr::Ident(ref id) => Expr::Ident(id.to_owned()), - Expr::Literal(ref lit) => Expr::Literal(lit.clone()), + Expr::Literal(ref lit) => Expr::Literal(lit.to_owned()), Expr::UnaryOp { op, rhs } => Expr::UnaryOp { op: *op, rhs: Box::new((**rhs).to_owned()), @@ -247,6 +258,7 @@ pub enum Type { Int, Float, Bool, + CString, Function(FunctionType), } @@ -256,6 +268,7 @@ impl Display for Type { Type::Int => f.write_str("int"), Type::Float => f.write_str("float"), Type::Bool => f.write_str("bool"), + Type::CString => f.write_str("cstring"), Type::Function(ft) => ft.fmt(f), } } diff --git a/src/codegen/llvm.rs b/src/codegen/llvm.rs index 5b5db90a1ad8..ee087845b640 100644 --- a/src/codegen/llvm.rs +++ b/src/codegen/llvm.rs @@ -92,6 +92,7 @@ impl<'ctx, 'ast> Codegen<'ctx, 'ast> { Literal::Bool(b) => Ok(AnyValueEnum::IntValue( ty.const_int(if *b { 1 } else { 0 }, false), )), + Literal::String(_) => todo!(), } } Expr::UnaryOp { op, rhs, .. } => { diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 85a8928cbf9a..d414dedf8560 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -29,6 +29,7 @@ impl<'a> Interpreter<'a> { Expr::Ident(id, _) => self.resolve(id), Expr::Literal(Literal::Int(i), _) => Ok((*i).into()), Expr::Literal(Literal::Bool(b), _) => Ok((*b).into()), + Expr::Literal(Literal::String(s), _) => Ok(s.clone().into()), Expr::UnaryOp { op, rhs, .. } => { let rhs = self.eval(rhs)?; match op { diff --git a/src/interpreter/value.rs b/src/interpreter/value.rs index 5e55825160cd..a1a579aec8db 100644 --- a/src/interpreter/value.rs +++ b/src/interpreter/value.rs @@ -1,7 +1,9 @@ +use std::borrow::Cow; use std::convert::TryFrom; use std::fmt::{self, Display}; use std::ops::{Add, Div, Mul, Neg, Sub}; use std::rc::Rc; +use std::result; use derive_more::{Deref, From, TryInto}; @@ -22,15 +24,28 @@ pub enum Val<'a> { Int(i64), Float(f64), Bool(bool), + String(Cow<'a, str>), Function(Function<'a>), } +impl<'a> TryFrom<Val<'a>> for String { + type Error = (); + + fn try_from(value: Val<'a>) -> result::Result<Self, Self::Error> { + match value { + Val::String(s) => Ok(s.into_owned()), + _ => Err(()), + } + } +} + impl<'a> fmt::Debug for Val<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Val::Int(x) => f.debug_tuple("Int").field(x).finish(), Val::Float(x) => f.debug_tuple("Float").field(x).finish(), Val::Bool(x) => f.debug_tuple("Bool").field(x).finish(), + Val::String(s) => f.debug_tuple("String").field(s).finish(), Val::Function(Function { type_, .. }) => { f.debug_struct("Function").field("type_", type_).finish() } @@ -62,6 +77,7 @@ impl<'a> Display for Val<'a> { Val::Int(x) => x.fmt(f), Val::Float(x) => x.fmt(f), Val::Bool(x) => x.fmt(f), + Val::String(s) => write!(f, "{:?}", s), Val::Function(Function { type_, .. }) => write!(f, "<{}>", type_), } } @@ -73,6 +89,7 @@ impl<'a> Val<'a> { Val::Int(_) => Type::Int, Val::Float(_) => Type::Float, Val::Bool(_) => Type::Bool, + Val::String(_) => Type::CString, Val::Function(Function { type_, .. }) => Type::Function(type_.clone()), } } @@ -178,3 +195,9 @@ impl TypeOf for f64 { Type::Float } } + +impl TypeOf for String { + fn type_of() -> Type { + Type::CString + } +} diff --git a/src/main.rs b/src/main.rs index d5b00d6b6c46..d476b96ed634 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +#![feature(str_split_once)] + use clap::Clap; pub mod ast; diff --git a/src/parser/expr.rs b/src/parser/expr.rs index 73c873b5b304..2ec6d60cd04f 100644 --- a/src/parser/expr.rs +++ b/src/parser/expr.rs @@ -1,11 +1,14 @@ +use std::borrow::Cow; + +use nom::alt; use nom::character::complete::{digit1, multispace0, multispace1}; use nom::{ - alt, call, char, complete, delimited, do_parse, flat_map, many0, map, named, opt, parse_to, + call, char, complete, delimited, do_parse, flat_map, many0, map, named, opt, parse_to, preceded, separated_list0, separated_list1, tag, tuple, }; use pratt::{Affix, Associativity, PrattParser, Precedence}; -use crate::ast::{BinaryOperator, Binding, Expr, Fun, Ident, Literal, UnaryOperator}; +use crate::ast::{BinaryOperator, Binding, Expr, Fun, Literal, UnaryOperator}; use crate::parser::{ident, type_}; #[derive(Debug)] @@ -161,7 +164,22 @@ named!(bool_(&str) -> Literal, alt!( tag!("false") => { |_| Literal::Bool(false) } )); -named!(literal(&str) -> Literal, alt!(int | bool_)); +fn string_internal(i: &str) -> nom::IResult<&str, Cow<'_, str>, nom::error::Error<&str>> { + let (s, rem) = i + .split_once('"') + .ok_or_else(|| nom::Err::Error(nom::error::Error::new(i, nom::error::ErrorKind::Tag)))?; + Ok((rem, Cow::Borrowed(s))) +} + +named!(string(&str) -> Literal, preceded!( + char!('"'), + map!( + string_internal, + |s| Literal::String(s) + ) +)); + +named!(literal(&str) -> Literal, alt!(int | bool_ | string)); named!(literal_expr(&str) -> Expr, map!(literal, Expr::Literal)); @@ -308,7 +326,7 @@ named!(pub expr(&str) -> Expr, alt!( #[cfg(test)] pub(crate) mod tests { use super::*; - use crate::ast::Type; + use crate::ast::{Ident, Type}; use std::convert::TryFrom; use BinaryOperator::*; use Expr::{BinaryOp, If, Let, UnaryOp}; @@ -419,6 +437,14 @@ pub(crate) mod tests { } #[test] + fn simple_string_lit() { + assert_eq!( + test_parse!(expr, "\"foobar\""), + Expr::Literal(Literal::String(Cow::Borrowed("foobar"))) + ) + } + + #[test] fn let_complex() { let res = test_parse!(expr, "let x = 1; y = x * 7 in (x + y) * 4"); assert_eq!( diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 0251d02df464..9ac590cee86c 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -16,7 +16,17 @@ pub type Error = nom::Err<nom::error::Error<String>>; pub(crate) fn is_reserved(s: &str) -> bool { matches!( s, - "if" | "then" | "else" | "let" | "in" | "fn" | "int" | "float" | "bool" | "true" | "false" + "if" | "then" + | "else" + | "let" + | "in" + | "fn" + | "int" + | "float" + | "bool" + | "true" + | "false" + | "cstring" ) } diff --git a/src/parser/type_.rs b/src/parser/type_.rs index 076df7d6bd55..66b4f9f72c23 100644 --- a/src/parser/type_.rs +++ b/src/parser/type_.rs @@ -27,6 +27,7 @@ named!(pub type_(&str) -> Type, alt!( tag!("int") => { |_| Type::Int } | tag!("float") => { |_| Type::Float } | tag!("bool") => { |_| Type::Bool } | + tag!("cstring") => { |_| Type::CString } | function_type | delimited!( tuple!(tag!("("), multispace0), @@ -44,6 +45,7 @@ mod tests { assert_eq!(test_parse!(type_, "int"), Type::Int); assert_eq!(test_parse!(type_, "float"), Type::Float); assert_eq!(test_parse!(type_, "bool"), Type::Bool); + assert_eq!(test_parse!(type_, "cstring"), Type::CString); } #[test] diff --git a/src/tc/mod.rs b/src/tc/mod.rs index b5acfac2b426..2c40a02bf7c6 100644 --- a/src/tc/mod.rs +++ b/src/tc/mod.rs @@ -49,6 +49,7 @@ pub enum PrimType { Int, Float, Bool, + CString, } impl From<PrimType> for ast::Type { @@ -57,6 +58,7 @@ impl From<PrimType> for ast::Type { PrimType::Int => ast::Type::Int, PrimType::Float => ast::Type::Float, PrimType::Bool => ast::Type::Bool, + PrimType::CString => ast::Type::CString, } } } @@ -67,6 +69,7 @@ impl Display for PrimType { PrimType::Int => f.write_str("int"), PrimType::Float => f.write_str("float"), PrimType::Bool => f.write_str("bool"), + PrimType::CString => f.write_str("cstring"), } } } @@ -125,6 +128,7 @@ impl TryFrom<Type> for ast::Type { const INT: Type = Type::Prim(PrimType::Int); const FLOAT: Type = Type::Prim(PrimType::Float); const BOOL: Type = Type::Prim(PrimType::Bool); +const CSTRING: Type = Type::Prim(PrimType::CString); impl Display for Type { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -144,6 +148,7 @@ impl From<ast::Type> for Type { ast::Type::Int => INT, ast::Type::Float => FLOAT, ast::Type::Bool => BOOL, + ast::Type::CString => CSTRING, ast::Type::Function(ast::FunctionType { args, ret }) => Type::Fun { args: args.into_iter().map(Self::from).collect(), ret: Box::new(Self::from(*ret)), @@ -181,8 +186,9 @@ impl<'ast> Typechecker<'ast> { let type_ = match lit { Literal::Int(_) => Type::Prim(PrimType::Int), Literal::Bool(_) => Type::Prim(PrimType::Bool), + Literal::String(_) => Type::Prim(PrimType::CString), }; - Ok(hir::Expr::Literal(lit, type_)) + Ok(hir::Expr::Literal(lit.to_owned(), type_)) } ast::Expr::UnaryOp { op, rhs } => todo!(), ast::Expr::BinaryOp { lhs, op, rhs } => { |