diff --git a/README.md b/README.md index dd3460f..28617aa 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ This language is under active development, progress will be marked here as the l - [x] Functions - [x] Int Literals - [x] Float Literals +- [x] String Literals - [x] Block expression - [x] Return keyword - [x] Normal assignment diff --git a/examples/strings.bl b/examples/strings.bl new file mode 100644 index 0000000..bbc4877 --- /dev/null +++ b/examples/strings.bl @@ -0,0 +1,5 @@ + + +fn main(): String { + return "foo"; +} diff --git a/src/ast.rs b/src/ast.rs index 8037f56..a2d63ca 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -172,6 +172,12 @@ pub struct LiteralBool { pub type_: TypeUsage, } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct LiteralString { + pub value: Spanned, + pub type_: TypeUsage, +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct LiteralStruct { pub type_parameters: GenericUsage, @@ -227,6 +233,7 @@ pub enum Subexpression { LiteralInt(LiteralInt), LiteralFloat(LiteralFloat), LiteralBool(LiteralBool), + LiteralString(LiteralString), LiteralStruct(LiteralStruct), FunctionCall(FunctionCall), VariableUsage(VariableUsage), diff --git a/src/builtins.rs b/src/builtins.rs index 473368c..c389d01 100644 --- a/src/builtins.rs +++ b/src/builtins.rs @@ -1 +1,3 @@ use std::collections::HashMap; + +use crate::ast; diff --git a/src/grammar.lalrpop b/src/grammar.lalrpop index 73a2bfc..3b5f5ad 100644 --- a/src/grammar.lalrpop +++ b/src/grammar.lalrpop @@ -34,6 +34,8 @@ match { "struct", "impl", ",", + r"'(\\'|[^'])*'", + r#""(\\"|[^"])*""#, r"\s*" => { }, r"//[^\n\r]*[\n\r]*" => { }, // `// comment` @@ -65,6 +67,16 @@ pub SpannedLiteralBool: ast::LiteralBool = { > => ast::LiteralBool{value: literal_bool, type_: ast::TypeUsage::new_builtin("bool".to_string())} }; +pub LiteralString: String = { + => String::from(&s[1..s.len()-1]), + => String::from(&s[1..s.len()-1]), +}; + +pub SpannedLiteralString: ast::LiteralString = { + > => ast::LiteralString{value: literal_string, type_: ast::TypeUsage::new_builtin("String".to_string())} +}; + + pub Identifier: String = { => i.to_string() }; @@ -163,6 +175,7 @@ pub Term: ast::Expression = { SpannedLiteralInt => ast::Expression{subexpression: Box::new(ast::Subexpression::LiteralInt(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)}, SpannedLiteralFloat => ast::Expression{subexpression: Box::new(ast::Subexpression::LiteralFloat(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)}, SpannedLiteralBool => ast::Expression{subexpression: Box::new(ast::Subexpression::LiteralBool(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)}, + SpannedLiteralString => ast::Expression{subexpression: Box::new(ast::Subexpression::LiteralString(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)}, LiteralStruct => ast::Expression{subexpression: Box::new(ast::Subexpression::LiteralStruct(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)}, FunctionCall => ast::Expression{subexpression: Box::new(ast::Subexpression::FunctionCall(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)}, StructGetter => ast::Expression{subexpression: Box::new(ast::Subexpression::StructGetter(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)}, diff --git a/src/interpreter.rs b/src/interpreter.rs index 3179010..aa49d6b 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -44,6 +44,7 @@ pub struct Function { pub enum Value { Numeric(NumericValue), Bool(bool), + String(String), Function(Function), Struct(Arc>), Unit, @@ -207,6 +208,12 @@ fn create_builtins() -> HashMap { name: "!".to_string(), })), ); + result.insert( + "String".to_string(), + NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration { + name: "String".to_string(), + })), + ); return result; } @@ -331,6 +338,10 @@ impl TreeWalkInterpreter { let value: bool = if &literal_bool.value.value == "true" { true } else { false }; return ExpressionResult::Value(Value::Bool(value)); } + ast::Subexpression::LiteralString(literal_string) => { + let value: String = literal_string.value.value.to_string(); + return ExpressionResult::Value(Value::String(value)); + } ast::Subexpression::LiteralStruct(literal_struct) => { let declaration = match &ctx.environment[&literal_struct.name.name.value] { NamedEntity::TypeDeclaration(ast::TypeDeclaration::Struct(declaration)) => declaration.clone(), diff --git a/src/type_alias_resolution.rs b/src/type_alias_resolution.rs index 69e7f35..29d55bc 100644 --- a/src/type_alias_resolution.rs +++ b/src/type_alias_resolution.rs @@ -308,6 +308,10 @@ impl TypeAliasResolver { value: literal_bool.value.clone(), type_: process_type(ctx, &literal_bool.type_)?, }), + ast::Subexpression::LiteralString(literal_string) => ast::Subexpression::LiteralString(ast::LiteralString { + value: literal_string.value.clone(), + type_: process_type(ctx, &literal_string.type_)?, + }), ast::Subexpression::LiteralStruct(literal_struct) => { let result = resolve_type( ctx, diff --git a/src/type_checking.rs b/src/type_checking.rs index 8a0e2c8..35e5cc3 100644 --- a/src/type_checking.rs +++ b/src/type_checking.rs @@ -386,6 +386,15 @@ fn create_builtins() -> HashMap { impls: vec![], }), ); + result.insert( + "String".to_string(), + NamedEntity::NamedType(EnvType { + generic: ast::Generic{parameters: vec!()}, + is_a: TypeType::Scalar, + fields: HashMap::new(), + impls: vec![], + }), + ); return result; } @@ -1215,6 +1224,12 @@ impl TypeChecker { substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &expression.type_, &result.type_)?)?; ast::Subexpression::LiteralBool(result) } + ast::Subexpression::LiteralString(literal_string) => { + let (result, subst) = self.with_literal_string(ctx, &substitution, literal_string)?; + substitution = compose_substitutions(ctx, &substitution, &subst)?; + substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &expression.type_, &result.type_)?)?; + ast::Subexpression::LiteralString(result) + } ast::Subexpression::LiteralStruct(literal_struct) => { let (result, subst) = self.with_literal_struct(ctx, &substitution, literal_struct)?; substitution = compose_substitutions(ctx, &substitution, &subst)?; @@ -1312,6 +1327,21 @@ impl TypeChecker { )) } + fn with_literal_string( + self: &Self, + ctx: &Context, + substitution: &SubstitutionMap, + literal_string: &ast::LiteralString, + ) -> Result<(ast::LiteralString, SubstitutionMap)> { + Ok(( + ast::LiteralString { + value: literal_string.value.clone(), + type_: apply_substitution(ctx, &substitution, &literal_string.type_)?, + }, + substitution.clone(), + )) + } + fn with_literal_struct( self: &Self, ctx: &Context,