diff --git a/lib/AST.hs b/lib/AST.hs index 3fe73b9..0062aae 100644 --- a/lib/AST.hs +++ b/lib/AST.hs @@ -38,7 +38,7 @@ data Expr | Discard Expr | Import {objects :: [String], from :: String, qualified :: Bool, as :: Maybe String} | Ref Expr - | Struct {name :: String, fields :: [(String, Type)], refinement :: Maybe Expr, refinementSrc :: String} + | Struct {name :: String, fields :: [(String, Type)], refinement :: Maybe Expr, refinementSrc :: String, is :: [String]} | StructLit String [(String, Expr)] Position | StructAccess Expr Expr | ListLit [Expr] diff --git a/lib/BytecodeCompiler.hs b/lib/BytecodeCompiler.hs index f49aea3..b8481ba 100644 --- a/lib/BytecodeCompiler.hs +++ b/lib/BytecodeCompiler.hs @@ -432,9 +432,10 @@ compileExpr (Parser.Cast from to) = do compileType (Parser.Var "CPtr" _) = [Push $ DCPtr $ ptrToWordPtr nullPtr] compileType (Parser.ListLit [x]) = compileType x ++ [PackList 1] compileType x = error $ "Type " ++ show x ++ " is not implemented" -compileExpr st@(Parser.Struct{fields}) = do +compileExpr st@(Parser.Struct{name = structName, fields, is}) = do modify (\s -> s{structDecs = st : structDecs s}) mapM_ createFieldTrait fields + mapM_ (compileExpr . (\t -> Parser.Impl{methods = [], for = structName, trait = t})) is return [] where createFieldTrait :: (String, Parser.Type) -> StateT (CompilerState a) IO () diff --git a/lib/Parser.hs b/lib/Parser.hs index 6335dca..ce79ed1 100644 --- a/lib/Parser.hs +++ b/lib/Parser.hs @@ -359,7 +359,10 @@ struct = do refinement <- optional $ do keyword "satisfies" parens expr - return $ Struct{name = name, fields = fields, refinement = refinement, refinementSrc = fromMaybe "" refinementSrc} + is <- optional $ do + keyword "is" + sepBy extra (symbol ",") + return $ Struct{name = name, fields = fields, refinement = refinement, refinementSrc = fromMaybe "" refinementSrc, is = fromMaybe [] is} where structField = do fieldName <- identifier "field name" diff --git a/tests/IntegrationSpec.hs b/tests/IntegrationSpec.hs index 802a66a..5a06d4a 100644 --- a/tests/IntegrationSpec.hs +++ b/tests/IntegrationSpec.hs @@ -189,6 +189,14 @@ spec = do println name mauzi end|] `shouldReturn` "Mauzi\n" + it "Can use `is` syntax" $ do + compileAndRun + [r| + trait Person + trait Human + struct Person = (name: String, age: Int) is Person, Human + |] + `shouldReturn` "" describe "Traits" $ do it "Can use a trait" $ do compileAndRun diff --git a/tests/ParserSpec.hs b/tests/ParserSpec.hs index fa28a77..390a9e2 100644 --- a/tests/ParserSpec.hs +++ b/tests/ParserSpec.hs @@ -59,6 +59,15 @@ spec = do parseProgram "bello{}.name" parserCompilerFlags `shouldBe` Right (Program [StructAccess (StructLit "bello" [] anyPosition) (Var "name" anyPosition)]) + it "Can define" $ + parseProgram "struct Teacher = ()" parserCompilerFlags + `shouldBe` Right (Program [Struct{name = "Teacher", fields = [], refinement = Nothing, refinementSrc = "", is = []}]) + it "Can define with is" $ do + parseProgram "struct Teacher = () is Person" parserCompilerFlags + `shouldBe` Right (Program [Struct{name = "Teacher", fields = [], refinement = Nothing, refinementSrc = "", is = ["Person"]}]) + it "Can define with multiple is" $ do + parseProgram "struct Teacher = () is Person, Employee" parserCompilerFlags + `shouldBe` Right (Program [Struct{name = "Teacher", fields = [], refinement = Nothing, refinementSrc = "", is = ["Person", "Employee"]}]) describe "Traits" $ do it "Should parse a trait decleration" $ parseProgram "trait Show = do\nshow :: Self -> String\nend" parserCompilerFlags