diff --git a/rfruit/.gitignore b/.gitignore similarity index 100% rename from rfruit/.gitignore rename to .gitignore diff --git a/rfruit/Cargo.toml b/Cargo.toml similarity index 63% rename from rfruit/Cargo.toml rename to Cargo.toml index 0318d81..0d157d8 100644 --- a/rfruit/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "rfruit" +name = "frugurt" version = "0.1.0" edition = "2021" @@ -10,6 +10,13 @@ clap = { version = "4.5.4", features = ["derive"] } once_cell = "1.19.0" serde_json = "1.0.115" thiserror = "1.0.58" +tree-sitter = "0.22.5" +proc-macro2 = "1.0.78" +tree-sitter-frugurt = "0.0.3" +#tree-sitter-frugurt = { path = "../tree-sitter-frugurt" } [dev-dependencies] tempfile = "3.10.1" + +[build-dependencies] +cc = "*" diff --git a/README.md b/README.md index aa52f84..1467923 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ -### Frugurt is interpreted language, with focus on functional and OOP. +### Frugurt is an interpreted language, with focus on functional and OOP. > It is proof of concept, showing interesting features, in active development still -The main purpose of Frugurt is to present entirely different approach to OOP, than in other languages like Python or JavaScript. +The main purpose of Frugurt is to present an entirely different approach to OOP, +compared to other languages like Python or JavaScript. Example @@ -30,14 +31,14 @@ All types have fixed schema, that means: - All fields must be declared at once - Any other fields can never be declared -Also, there are 3 flavors of types: +Also, there are three flavors of types: - struct - mutable, passed by value - class - mutable, passed by reference - data - immutable, passed by reference -There is also builtin data validation, using "watches", see [docs](https://leokostarev.github.io/frugurt-lang/03-object-oriented-programming/06-watches.html). - +There is also builtin data validation, using "watches", +see [docs](https://frugurt-lang.github.io/frugurt/03-object-oriented-programming/06-watches.html). ```frugurt struct Vector { diff --git a/converter/.gitignore b/converter/.gitignore deleted file mode 100644 index d84a5aa..0000000 --- a/converter/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/.stack-work \ No newline at end of file diff --git a/converter/Setup.hs b/converter/Setup.hs deleted file mode 100644 index 9a994af..0000000 --- a/converter/Setup.hs +++ /dev/null @@ -1,2 +0,0 @@ -import Distribution.Simple -main = defaultMain diff --git a/converter/converter.cabal b/converter/converter.cabal deleted file mode 100644 index 859b843..0000000 --- a/converter/converter.cabal +++ /dev/null @@ -1,36 +0,0 @@ -cabal-version: 3.8 -name: converter -version: 0.1.0.0 -homepage: https://github.com/leokostarev/frugurt-lang -license: MIT -author: Leonid Kostarev -maintainer: leokostarev@mail.ru -copyright: 2024 Leonid Kostarev -build-type: Simple -category: Parser - -executable converter - hs-source-dirs: src - main-is: Main.hs - other-modules: - Debugize - Jsonize - Tokenize - Treeanize - - default-language: Haskell2010 - build-depends: - , aeson - , base >=4.7 && <5 - , binary - , bytestring - , containers - , megaparsec - , parsec - , scientific - , text - - ghc-options: - -Wall -Wcompat -Widentities -Wincomplete-record-updates - -Wincomplete-uni-patterns -Wmissing-export-lists - -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints diff --git a/converter/fourmolu.yaml b/converter/fourmolu.yaml deleted file mode 100644 index e894d98..0000000 --- a/converter/fourmolu.yaml +++ /dev/null @@ -1,51 +0,0 @@ -# Number of spaces per indentation step -indentation: 2 - -# Max line length for automatic line breaking -column-limit: 120 - -# Styling of arrows in type signatures (choices: trailing, leading, or leading-args) -function-arrows: trailing - -# How to place commas in multi-line lists, records, etc. (choices: leading or trailing) -comma-style: leading - -# Styling of import/export lists (choices: leading, trailing, or diff-friendly) -import-export-style: leading - -# Whether to full-indent or half-indent 'where' bindings past the preceding body -indent-wheres: true - -# Whether to leave a space before an opening record brace -record-brace-space: false - -# Number of spaces between top-level declarations -newlines-between-decls: 2 - -# How to print Haddock comments (choices: single-line, multi-line, or multi-line-compact) -haddock-style: multi-line - -# How to print module docstring -haddock-style-module: null - -# Styling of let blocks (choices: auto, inline, newline, or mixed) -let-style: auto - -# How to align the 'in' keyword with respect to the 'let' keyword (choices: left-align, right-align, or no-space) -in-style: right-align - -# Whether to put parentheses around a single constraint (choices: auto, always, or never) -single-constraint-parens: always - -# Output Unicode syntax (choices: detect, always, or never) -unicode: never - -# Give the programmer more choice on where to insert blank lines -respectful: true - -# Fixity information for operators -fixities: [] - -# Module reexports Fourmolu should know about -reexports: [] - diff --git a/converter/src/Debugize.hs b/converter/src/Debugize.hs deleted file mode 100644 index d7288f4..0000000 --- a/converter/src/Debugize.hs +++ /dev/null @@ -1,201 +0,0 @@ -{-# LANGUAGE LambdaCase #-} - -module Debugize (toDbgStrStmt) where - -import Data.List (intercalate) -import Data.Maybe (isJust) -import Treeanize (FruExpr (..), FruField (..), FruMethod (..), FruStmt (..), FruWatch (..)) - - -getSpace :: Int -> String -getSpace indent = concat $ replicate indent "| " - - -toDbgStrField :: Int -> FruField -> String -toDbgStrField indent (FruField isPub isStatic name typeIdent) = - getSpace indent - ++ (if isPub then "pub " else "") - ++ (if isJust isStatic then "static " else "") - ++ name - ++ ( case typeIdent of - Nothing -> "" - Just ident -> " : " ++ ident - ) - ++ (case isStatic of Just (Just v) -> " =\n" ++ toDbgStrExpr (indent + 1) v; _ -> "\n") - - -toDbgWatch :: Int -> FruWatch -> String -toDbgWatch indent (FruWatch fields body) = - getSpace indent - ++ "Watch:\n" - ++ getSpace (indent + 1) - ++ "fields: " - ++ intercalate ", " fields - ++ "\n" - ++ getSpace (indent + 1) - ++ "body:\n" - ++ toDbgStrStmt (indent + 2) body - - -toDbgStrMethod :: Int -> FruMethod -> String -toDbgStrMethod indent (FruMethod name args body) = - getSpace indent - ++ "Method:\n" - ++ getSpace (indent + 1) - ++ "name: " - ++ name - ++ "\n" - ++ getSpace (indent + 1) - ++ "args: " - ++ intercalate ", " args - ++ "\n" - ++ getSpace (indent + 1) - ++ "body:\n" - ++ toDbgStrStmt (indent + 2) body - - -toDbgStrProperty :: Int -> String -> a -> (Int -> a -> String) -> String -toDbgStrProperty indent name value toString = - getSpace (indent + 1) - ++ name - ++ ":\n" - ++ toString (indent + 2) value - - -toDbgStrStr :: Int -> String -> String -- TODO: make use of this everywhere -toDbgStrStr indent str = getSpace indent ++ str ++ "\n" - - -toDbgStrStmt :: Int -> FruStmt -> String -toDbgStrStmt indent = \case - StBlock stmts -> - getSpace indent - ++ "Block:\n" - ++ concatMap (toDbgStrStmt (indent + 1)) stmts - StNothing -> - getSpace indent - ++ "Nothing:\n" - StExpr e -> - getSpace indent - ++ "Expression:\n" - ++ toDbgStrExpr (indent + 1) e - StLet ident e -> - getSpace indent - ++ "Let:\n" - ++ toDbgStrProperty indent "ident" ident toDbgStrStr - ++ toDbgStrProperty indent "what" e toDbgStrExpr - StSet ident e -> - getSpace indent - ++ "Set:\n" - ++ toDbgStrProperty indent "path" ident toDbgStrStr - ++ toDbgStrProperty indent "what" e toDbgStrExpr - StSetField target field e -> - getSpace indent - ++ "SetField:\n" - ++ toDbgStrProperty indent "target" target toDbgStrExpr - ++ toDbgStrProperty indent "field" field toDbgStrStr - ++ toDbgStrProperty indent "what" e toDbgStrExpr - StIf cond thenBody elseBody -> - getSpace indent - ++ "If:\n" - ++ toDbgStrProperty indent "cond" cond toDbgStrExpr - ++ toDbgStrProperty indent "then" thenBody toDbgStrStmt - ++ toDbgStrProperty indent "else" elseBody toDbgStrStmt - StWhile cond body -> - getSpace indent - ++ "While:\n" - ++ toDbgStrProperty indent "cond" cond toDbgStrExpr - ++ toDbgStrProperty indent "body" body toDbgStrStmt - StReturn e -> - getSpace indent - ++ "Return:\n" - ++ toDbgStrExpr (indent + 1) e - StBreak -> - getSpace indent - ++ "Break\n" - StContinue -> - getSpace indent - ++ "Continue\n" - StOperator op commutative leftIdent leftType rightIdent rightType body -> - getSpace indent - ++ (if commutative then "Commutative " else "") - ++ "Operator:\n" - ++ toDbgStrProperty indent "op" op toDbgStrStr - ++ toDbgStrProperty indent "left" (leftIdent ++ " : " ++ leftType) toDbgStrStr - ++ toDbgStrProperty indent "right" (rightIdent ++ " : " ++ rightType) toDbgStrStr - ++ toDbgStrProperty indent "body" body toDbgStrStmt - StType typeType ident fields watches methods staticMethods -> - getSpace indent - ++ "Type:\n" - ++ toDbgStrProperty indent "type" typeType toDbgStrStr - ++ toDbgStrProperty indent "ident" ident toDbgStrStr - ++ getSpace (indent + 1) - ++ "fields:\n" - ++ concatMap (toDbgStrField (indent + 2)) fields - ++ getSpace (indent + 1) - ++ "watches:\n" - ++ concatMap (toDbgWatch (indent + 2)) watches - ++ getSpace (indent + 1) - ++ "methods:\n" - ++ concatMap (toDbgStrMethod (indent + 2)) methods - ++ getSpace (indent + 1) - ++ "static methods:\n" - ++ concatMap (toDbgStrMethod (indent + 2)) staticMethods - - -toDbgStrExpr :: Int -> FruExpr -> String -toDbgStrExpr indent = \case - ExLiteralNah -> getSpace indent ++ "nah\n" - ExLiteralNumber n -> getSpace indent ++ show n ++ "\n" - ExLiteralBool b -> getSpace indent ++ show b ++ "\n" - ExLiteralString s -> getSpace indent ++ show s ++ "\n" - ExVariable v -> getSpace indent ++ v ++ "\n" - ExBlock body expr -> - getSpace indent - ++ "Block:\n" - ++ concatMap (toDbgStrStmt (indent + 1)) body - ++ getSpace (indent + 1) - ++ "expression:\n" - ++ toDbgStrExpr (indent + 1) expr - ExCall e es -> - getSpace indent - ++ "Call:\n" - ++ toDbgStrProperty indent "what" e toDbgStrExpr - ++ getSpace (indent + 1) - ++ "args:\n" - ++ concatMap (toDbgStrExpr (indent + 2)) es - ExCurryCall e es -> - getSpace indent - ++ "CurryCall:\n" - ++ toDbgStrProperty indent "what" e toDbgStrExpr - ++ getSpace (indent + 1) - ++ "args:\n" - ++ concatMap (toDbgStrExpr (indent + 2)) es - ExBinaries f r -> - getSpace indent - ++ "Binaries:\n" - ++ toDbgStrExpr (indent + 1) f - ++ concatMap (\(op, ex) -> toDbgStrStr (indent + 1) op ++ toDbgStrExpr (indent + 1) ex) r - ExFunction args body -> - getSpace indent - ++ "Function:\n" - ++ toDbgStrProperty indent "args" (intercalate ", " args) toDbgStrStr - ++ toDbgStrProperty indent "body" body toDbgStrStmt - ExInstantiation e es -> - getSpace indent - ++ "Instantiation:\n" - ++ toDbgStrProperty indent "what" e toDbgStrExpr - ++ getSpace (indent + 1) - ++ "args:\n" - ++ concatMap (toDbgStrExpr (indent + 2)) es - ExFieldAccess e f -> - getSpace indent - ++ "FieldAccess:\n" - ++ toDbgStrProperty indent "what" e toDbgStrExpr - ++ toDbgStrProperty indent "field" f toDbgStrStr - ExIfElse condition thenBody elseBody -> - getSpace indent - ++ "IfElse:\n" - ++ toDbgStrProperty indent "condition" condition toDbgStrExpr - ++ toDbgStrProperty indent "then" thenBody toDbgStrExpr - ++ toDbgStrProperty indent "else" elseBody toDbgStrExpr diff --git a/converter/src/Jsonize.hs b/converter/src/Jsonize.hs deleted file mode 100644 index f80edf4..0000000 --- a/converter/src/Jsonize.hs +++ /dev/null @@ -1,214 +0,0 @@ -{-# LANGUAGE LambdaCase #-} - -module Jsonize (toJsonExpr, toJsonStmt, toString, JSON (..)) where - -import Data.List (intercalate) -import Data.Maybe (isJust) -import Data.Scientific (toRealFloat) -import Treeanize (FruExpr (..), FruField (..), FruMethod (..), FruStmt (..), FruWatch (..)) - - -data JSON - = Number Double - | Bool Bool - | Null - | Str String - | Array [JSON] - | Object [(String, JSON)] - deriving (Show, Eq) - - -toJsonExpr :: FruExpr -> JSON -toJsonExpr = \case - ExLiteralNah -> - Object - [ ("node", Str "literal") - , ("value", Null) - ] - ExLiteralNumber i -> - Object - [ ("node", Str "literal") - , ("value", Number $ toRealFloat i) - ] - ExLiteralBool b -> - Object - [ ("node", Str "literal") - , ("value", Bool b) - ] - ExLiteralString s -> - Object - [ ("node", Str "literal") - , ("value", Str s) - ] - ExVariable ident -> - Object - [ ("node", Str "variable") - , ("ident", Str ident) - ] - ExFunction args body -> - Object - [ ("node", Str "function") - , ("args", Array $ map Str args) - , ("body", toJsonStmt body) - ] - ExBlock body expr -> - Object - [ ("node", Str "block") - , ("body", Array $ map toJsonStmt body) - , ("expr", toJsonExpr expr) - ] - ExCall what args -> - Object - [ ("node", Str "call") - , ("what", toJsonExpr what) - , ("args", Array $ map toJsonExpr args) - ] - ExCurryCall what args -> - Object - [ ("node", Str "curry") - , ("what", toJsonExpr what) - , ("args", Array $ map toJsonExpr args) - ] - ExInstantiation what args -> - Object - [ ("node", Str "instantiation") - , ("what", toJsonExpr what) - , ("args", Array $ map toJsonExpr args) - ] - ExFieldAccess what field -> - Object - [ ("node", Str "field_access") - , ("what", toJsonExpr what) - , ("field", Str field) - ] - ExBinaries first rest -> - Object - [ ("node", Str "binaries") - , ("first", toJsonExpr first) - , ("rest", Array $ map (\(op, ex) -> Array [Str op, toJsonExpr ex]) rest) - ] - ExIfElse condition thenBody elseBody -> - Object - [ ("node", Str "if_expr") - , ("cond", toJsonExpr condition) - , ("then", toJsonExpr thenBody) - , ("else", toJsonExpr elseBody) - ] - - -toJsonStmt :: FruStmt -> JSON -toJsonStmt stmt = case stmt of - StBlock body -> - Object - [ ("node", Str "block") - , ("body", Array $ map toJsonStmt body) - ] - StNothing -> Object [("node", Str "nothing")] - StExpr expression -> - Object - [ ("node", Str "expression") - , ("value", toJsonExpr expression) - ] - StLet ident expression -> - Object - [ ("node", Str "let") - , ("ident", Str ident) - , ("value", toJsonExpr expression) - ] - StSet ident expression -> - Object - [ ("node", Str "set") - , ("ident", Str ident) - , ("value", toJsonExpr expression) - ] - StSetField target field expression -> - Object - [ ("node", Str "set_field") - , ("target", toJsonExpr target) - , ("field", Str field) - , ("value", toJsonExpr expression) - ] - StIf cond thenBody elseBody -> - Object - [ ("node", Str "if") - , ("cond", toJsonExpr cond) - , ("then", toJsonStmt thenBody) - , ("else", toJsonStmt elseBody) - ] - StWhile cond body -> - Object - [ ("node", Str "while") - , ("cond", toJsonExpr cond) - , ("body", toJsonStmt body) - ] - StReturn expression -> - Object - [ ("node", Str "return") - , ("value", toJsonExpr expression) - ] - StBreak -> Object [("node", Str "break")] - StContinue -> Object [("node", Str "continue")] - StOperator op commutative left_arg left_type right_arg right_type body -> - Object - [ ("node", Str "operator") - , ("ident", Str op) - , ("commutative", Bool commutative) - , ("left_ident", Str left_arg) - , ("left_type_ident", Str left_type) - , ("right_ident", Str right_arg) - , ("right_type_ident", Str right_type) - , ("body", toJsonStmt body) - ] - StType t ident fields watches methods staticMethods -> - Object - [ ("node", Str "type") - , ("type", Str t) - , ("ident", Str ident) - , ("fields", Array $ map toJsonField fields) - , ("watches", Array $ map toJsonWatch watches) - , ("methods", Array $ map toJsonMethod methods) - , ("static_methods", Array $ map toJsonMethod staticMethods) - ] - - -toJsonField :: FruField -> JSON -toJsonField (FruField isPub static ident typeIdent) = - Object $ - [ ("is_pub", Bool isPub) - , ("is_static", Bool $ isJust static) - , ("ident", Str ident) - ] - ++ (case typeIdent of Just typeIdent_ -> [("type_ident", Str typeIdent_)]; _ -> []) - ++ (case static of Just (Just v) -> [("value", toJsonExpr v)]; _ -> []) - - -toJsonWatch :: FruWatch -> JSON -toJsonWatch (FruWatch flds body) = Object [("fields", Array $ map Str flds), ("body", toJsonStmt body)] - - -toJsonMethod :: FruMethod -> JSON -toJsonMethod (FruMethod name args body) = - Object - [ ("ident", Str name) - , ("args", Array $ map Str args) - , ("body", toJsonStmt body) - ] - - -toString :: JSON -> String -toString (Number i) = show i -toString (Bool b) - | b = "true" - | otherwise = "false" -toString Null = "null" -toString (Str s) = show s -toString (Array xs) = - "[" - ++ intercalate ", " (map toString xs) - ++ "]" -toString (Object xs) = - "{" - ++ intercalate - ", " - (map (\(k, v) -> "\"" ++ k ++ "\"" ++ ": " ++ toString v) xs) - ++ "}" \ No newline at end of file diff --git a/converter/src/Main.hs b/converter/src/Main.hs deleted file mode 100644 index f058a72..0000000 --- a/converter/src/Main.hs +++ /dev/null @@ -1,88 +0,0 @@ -module Main - ( main - ) where - -import Control.Monad (unless, when) -import Data.Aeson (encode, object, (.=)) -import Data.Aeson.Key (fromString) -import Data.ByteString.Lazy.Char8 (unpack) -import Data.Either (fromLeft, fromRight, isLeft) -import Data.List (intercalate) -import Debugize (toDbgStrStmt) -import Jsonize (toJsonStmt, toString) -import System.Environment (getArgs) -import System.Exit (exitFailure) -import Text.Megaparsec (parse) -import Tokenize (fruTokenize) -import Treeanize (toAst) - - -possibleFlags :: [String] -possibleFlags = ["--debug"] - - -main :: IO () -main = do - allAarguments <- getArgs - when (null allAarguments) $ do - print "No source files specified" - exitFailure - - let filename = head allAarguments - let arguments = tail allAarguments - let unknownFlags = filter (`notElem` possibleFlags) arguments - - unless (null unknownFlags) $ do - print $ "Unknown flags: " ++ intercalate ", " unknownFlags - exitFailure - - let debugFlag = "--debug" `elem` arguments - - rawFile <- readFile filename - - -- tokens -- - let tokensOrError = parse fruTokenize filename rawFile - when (isLeft tokensOrError) $ do - let tokenizingError = fromLeft undefined tokensOrError - - when debugFlag $ do - putStrLn "---------- ERROR WHILE TOKENIZING ----------" - print tokensOrError - - unless debugFlag $ do - (putStrLn . unpack . encode . object) - [ fromString "error" .= "tokenizing" - , fromString "message" .= show tokenizingError - ] - exitFailure - - let tokens = fromRight undefined tokensOrError - - when debugFlag $ do - putStrLn "---------- TOKENS ----------" - putStrLn (intercalate "\n" $ map (("| " ++) . show) tokens) - - -- ast -- - let astOrError = parse toAst filename tokens - when (isLeft astOrError) $ do - let treeanizingError = fromLeft undefined astOrError - - when debugFlag $ do - putStrLn "---------- ERROR WHILE TREEANIZING ----------" - print astOrError - - unless debugFlag $ do - (putStrLn . unpack . encode . object) - [ fromString "error" .= "treeanizing" - , fromString "message" .= show treeanizingError - ] - exitFailure - - let ast = fromRight undefined astOrError - - when debugFlag $ do - putStrLn "---------- AST ------------" - putStrLn (toDbgStrStmt 0 ast) - - unless debugFlag $ do - putStrLn (toString $ toJsonStmt ast) diff --git a/converter/src/Tokenize.hs b/converter/src/Tokenize.hs deleted file mode 100644 index 486b0a9..0000000 --- a/converter/src/Tokenize.hs +++ /dev/null @@ -1,130 +0,0 @@ -module Tokenize - ( fruTokenize - , FruToken (..) - ) where - -import Data.Char (isAlpha, isAlphaNum) -import Data.Scientific (Scientific) -import Data.Void (Void) -import Text.Megaparsec - ( MonadParsec (..) - , Parsec - , choice - , many - , manyTill - , satisfy - , () - ) -import Text.Megaparsec.Char (char, space1, string) -import qualified Text.Megaparsec.Char.Lexer as L - - -opChars :: String -opChars = "+-*/%=<>&|^!?" - - -data FruToken - = TkNah -- primitives - | TkNumber Scientific - | TkBool Bool - | TkString String - | TkOp String -- operator - | TkLet -- keywords - | TkWhile - | TkReturn - | TkIf - | TkElse - | TkFn - | TkOperator - | TkCommutative - | TkBreak - | TkContinue - | TkStruct - | TkPub - | TkStatic - | TkConstraintsSection - | TkWatch - | TkImplSection - | TkStaticSection - | TkBraceOpen -- punctuation - | TkBraceClose - | TkColonBraceOpen - | TkParenOpen - | TkParenClose - | TkDollarParenOpen - | TkBracketOpen - | TkBracketClose - | TkSemiColon - | TkColon - | TkDot - | TkComma - | TkIdent String -- identifier - deriving (Eq, Ord, Show) - - -type Parser = Parsec Void String - - -sc :: Parser () -sc = L.space space1 (L.skipLineComment "//") (L.skipBlockComment "/*" "*/") - - -fruTokenize :: Parser [FruToken] -fruTokenize = - sc - *> many - ( choice - [ TkBraceOpen <$ char '{' -- punctuation - , TkBraceClose <$ char '}' - , TkColonBraceOpen <$ string ":{" - , TkParenOpen <$ char '(' - , TkParenClose <$ char ')' - , TkDollarParenOpen <$ string "$(" - , TkBracketOpen <$ char '[' - , TkBracketClose <$ char ']' - , TkSemiColon <$ char ';' - , TkColon <$ char ':' - , TkDot <$ char '.' - , TkComma <$ char ',' - , TkConstraintsSection <$ string "-----constraints-----" - , TkImplSection <$ string "-----impl-----" - , TkStaticSection <$ string "-----static-----" - , TkNumber <$> try literalNumber -- literals - , TkString <$> literalString - , TkOp <$> operator -- operator - , keywordOrIdent -- keyword or identifier - ] - <* sc - ) - <* eof - where - literalNumber = L.signed (return ()) L.scientific - - literalString :: Parser String - literalString = char '\"' *> manyTill L.charLiteral (char '\"') - - operator = takeWhile1P (Just "operator") (`elem` opChars) - - keywordOrIdent = do - firstSimbol <- satisfy (\c -> isAlpha c || c == '_') "identifier" - otherSymbols <- takeWhileP (Just "identifier") (\c -> isAlphaNum c || c == '_') - return $ - case firstSimbol : otherSymbols of - "nah" -> TkNah - "true" -> TkBool True - "false" -> TkBool False - "let" -> TkLet - "while" -> TkWhile - "return" -> TkReturn - "if" -> TkIf - "else" -> TkElse - "fn" -> TkFn - "operator" -> TkOperator - "commutative" -> TkCommutative - "break" -> TkBreak - "continue" -> TkContinue - "struct" -> TkStruct - "pub" -> TkPub - "static" -> TkStatic - "watch" -> TkWatch - name -> TkIdent name diff --git a/converter/src/Treeanize.hs b/converter/src/Treeanize.hs deleted file mode 100644 index 7d2fd76..0000000 --- a/converter/src/Treeanize.hs +++ /dev/null @@ -1,464 +0,0 @@ -{-# LANGUAGE LambdaCase #-} -{-# OPTIONS_GHC -Wno-partial-fields #-} - -module Treeanize (toAst, FruExpr (..), FruStmt (..), FruWatch (..), FruField (..), FruMethod (..)) where - -import Control.Monad (when) -import qualified Data.List.NonEmpty as NonEmpty -import Data.Maybe (isJust) -import Data.Scientific (Scientific) -import Data.Set (Set, singleton) -import Data.Void (Void) -import Text.Megaparsec - ( MonadParsec (eof, token, try) - , Parsec - , between - , choice - , failure - , many - , oneOf - , optional - , sepBy - , single - , (<|>) - ) -import Text.Megaparsec.Error (ErrorItem (Label)) -import Tokenize (FruToken (..)) - - -data FruExpr - = ExLiteralNah - | ExLiteralNumber Scientific - | ExLiteralBool Bool - | ExLiteralString String - | ExVariable String - | ExFunction [String] FruStmt - | ExBlock [FruStmt] FruExpr - | ExCall FruExpr [FruExpr] - | ExCurryCall FruExpr [FruExpr] - | ExInstantiation FruExpr [FruExpr] -- type object * field values - | ExFieldAccess FruExpr String - | ExBinaries FruExpr [(String, FruExpr)] - | ExIfElse FruExpr FruExpr FruExpr - deriving (Show, Eq) - - -data FruStmt - = StBlock [FruStmt] -- new scope always - | StNothing -- same as (StBlock []) - | StExpr FruExpr - | StLet String FruExpr - | StSet String FruExpr - | StSetField FruExpr String FruExpr - | StIf FruExpr FruStmt FruStmt -- always StBlock for 2 and 3 fields - | StWhile FruExpr FruStmt - | StReturn FruExpr - | StBreak - | StContinue - | StOperator String Bool String String String String FruStmt -- operator ident * is commutative * left ident * left type ident * right ident * right type ident * body - | StType - { getTypeType :: String - , getIdent :: String - , getFields :: [FruField] - , getWatches :: [FruWatch] - , getMethods :: [FruMethod] - , getStaticMethods :: [FruMethod] - } - deriving (Show, Eq) - - --- helpers - -makeErrSet :: String -> Set (ErrorItem FruToken) -makeErrSet = singleton . Label . NonEmpty.fromList - - -binaryOp :: Parsec Void [FruToken] String -binaryOp = token (\case TkOp "=" -> Nothing; TkOp x -> Just x; _ -> Nothing) (makeErrSet "bynary operator") - - --- oop stuff - -data FruField - = FruField Bool (Maybe (Maybe FruExpr)) String (Maybe String) -- is pub * is static && value * ident * type - deriving (Show, Eq) - - -data FruWatch - = FruWatch [String] FruStmt - deriving (Show, Eq) - - -data FruMethod - = FruMethod String [String] FruStmt - deriving (Show, Eq) - - -data TypeSection - = FieldsSection [FruField] - | ConstraintSection [FruWatch] - | ImplSection [FruMethod] - | StaticSection [FruMethod] - - -composeType :: FruToken -> String -> [TypeSection] -> FruStmt -composeType typeType ident = foldl applySection basicType - where - basicType = StType (typeTypeToStr typeType) ident [] [] [] [] - typeTypeToStr = \case - TkStruct -> "struct" - _ -> undefined - - applySection :: FruStmt -> TypeSection -> FruStmt - applySection to@(StType _ _ fields watches methods staticMethods) = \case - FieldsSection fields' -> to{getFields = fields ++ fields'} - ConstraintSection watches' -> to{getWatches = watches ++ watches'} - ImplSection methods' -> to{getMethods = methods ++ methods'} - StaticSection staticMethods' -> to{getStaticMethods = staticMethods ++ staticMethods'} - applySection _ = undefined - - --- parser - -type ParserStmt = Parsec Void [FruToken] FruStmt - - -type ParserExpr = Parsec Void [FruToken] FruExpr - - -type ParserExtExpr = Parsec Void [FruToken] (FruExpr -> FruExpr) - - -identifier :: Parsec Void [FruToken] String -identifier = token (\case TkIdent x -> Just x; _ -> Nothing) (makeErrSet "identifier") - - -toAst :: ParserStmt -toAst = program - where - program :: ParserStmt - program = do - stmts <- many statement <* eof - return $ StBlock stmts - - statement :: ParserStmt - statement = - choice - [ blockStmt - , try letStmt - , try setStmt - , try setFieldStmt - , try ifElseStmt - , try ifStmt - , try whileStmt - , try returnStmt - , try breakStmt - , try continueStmt - , try operatorStmt - , try typeStmt - , try exprStmt - ] - - blockStmt :: ParserStmt - blockStmt = - try $ - StBlock - <$> between - (single TkBraceOpen) - (single TkBraceClose) - (many statement) - - blockExpr :: ParserExpr - blockExpr = do - _ <- single TkBraceOpen - stmts <- many statement - expr <- expression - _ <- single TkBraceClose - - return $ ExBlock stmts expr - - functionBodyStmt :: ParserStmt - functionBodyStmt = blockStmt <|> (blockExprTransform <$> blockExpr) - where - blockExprTransform (ExBlock body expr) = StBlock $ body ++ [StReturn expr] - blockExprTransform _ = error "unreachable" - - exprStmt :: ParserStmt - exprStmt = do - ex <- expression - _ <- single TkSemiColon - return $ StExpr ex - - letStmt :: ParserStmt - letStmt = do - _ <- single TkLet - name <- identifier - _ <- single (TkOp "=") - value <- expression - _ <- single TkSemiColon - return $ StLet name value - - setStmt :: ParserStmt - setStmt = do - ident <- identifier - _ <- single (TkOp "=") - value <- expression - _ <- single TkSemiColon - return $ StSet ident value - - setFieldStmt :: ParserStmt - setFieldStmt = do - target <- expression - - when ((\case ExFieldAccess _ _ -> False; _ -> True) target) $ do - failure Nothing (makeErrSet "field access") - - let (target', field) = case target of - ExFieldAccess t f -> (t, f) - _ -> error "unreachable" - - _ <- single (TkOp "=") - value <- expression - _ <- single TkSemiColon - - return $ StSetField target' field value - - ifStmt :: ParserStmt - ifStmt = do - _ <- single TkIf - cond <- expression - thenBody <- blockStmt - return $ StIf cond thenBody StNothing - - ifElseStmt :: ParserStmt - ifElseStmt = do - _ <- single TkIf - cond <- expression - thenBody <- blockStmt - _ <- single TkElse - StIf cond thenBody <$> (blockStmt <|> ifElseStmt <|> ifStmt) - - whileStmt :: ParserStmt - whileStmt = do - _ <- single TkWhile - cond <- expression - StWhile cond <$> blockStmt - - returnStmt :: ParserStmt - returnStmt = do - _ <- single TkReturn - value <- expression - _ <- single TkSemiColon - return $ StReturn value - - breakStmt :: ParserStmt - breakStmt = StBreak <$ single TkBreak <* single TkSemiColon - - continueStmt :: ParserStmt - continueStmt = StContinue <$ single TkContinue <* single TkSemiColon - - operatorStmt :: ParserStmt - operatorStmt = do - commutative <- isJust <$> optional (single TkCommutative) - - _ <- single TkOperator - ident <- token (\case TkOp x -> Just x; _ -> Nothing) (makeErrSet "operator") - - _ <- single TkParenOpen - - leftIdent <- identifier - _ <- single TkColon - leftType <- identifier - - _ <- single TkComma - - rightIdent <- identifier - _ <- single TkColon - rightType <- identifier - - _ <- single TkParenClose - - StOperator ident commutative leftIdent leftType rightIdent rightType <$> functionBodyStmt - - typeStmt :: ParserStmt - typeStmt = do - typeType <- oneOf [TkStruct] - - ident <- identifier - _ <- single TkBraceOpen - - fields <- fieldsSection - sections <- many section - - _ <- single TkBraceClose - - return $ composeType typeType ident (fields : sections) - where - section = choice [constraintSection, implSection, staticSection] - - fieldsSection = do - fields <- many field - return $ FieldsSection fields - where - field = do - public <- isJust <$> optional (single TkPub) - static <- isJust <$> optional (single TkStatic) - ident <- identifier - fieldType <- optional (single TkColon *> identifier) - value <- optional (single (TkOp "=") *> expression) - - when (not static && isJust value) $ do - failure Nothing (makeErrSet "non-static field with value") - - let static' = if static then Just value else Nothing - - _ <- single TkSemiColon - return $ FruField public static' ident fieldType - - constraintSection = do - _ <- single TkConstraintsSection - watches <- many watch - return $ ConstraintSection watches - where - watch = do - _ <- single TkWatch - fields <- - between - (single TkParenOpen) - (single TkParenClose) - (sepBy identifier (single TkComma)) - FruWatch fields <$> blockStmt - - implSection = do - _ <- single TkImplSection - - methods <- many method - return $ ImplSection methods - - staticSection = do - _ <- single TkStaticSection - - methods <- many method - return $ StaticSection methods - - method = do - ident <- identifier - args <- - between - (single TkParenOpen) - (single TkParenClose) - (sepBy identifier (single TkComma)) - - FruMethod ident args <$> functionBodyStmt - - expression = do - first <- notBinaryExpr - rest <- many ((,) <$> binaryOp <*> notBinaryExpr) - - return $ if null rest then first else ExBinaries first rest - - notBinaryExpr :: ParserExpr - notBinaryExpr = do - ex <- simpleExpr - extensions <- many extensionExpr - - return $ foldl (flip ($)) ex extensions - where - simpleExpr :: ParserExpr - simpleExpr = - choice - [ litetalNah - , literalNumber - , literalBool - , literalString - , variableExpr - , blockExpr - , functionExpr - , ifElseExpr - ] - - extensionExpr :: ParserExtExpr - extensionExpr = - try $ - choice - [ callExpr - , curryCallExpr - , instantiationExpr - , fieldAccessExpr - ] - - litetalNah :: ParserExpr - litetalNah = ExLiteralNah <$ single TkNah - - literalNumber :: ParserExpr - literalNumber = ExLiteralNumber <$> token (\case TkNumber x -> Just x; _ -> Nothing) (makeErrSet "number") - - literalBool :: ParserExpr - literalBool = do - value <- token (\case TkBool x -> Just x; _ -> Nothing) (makeErrSet "bool") - return $ ExLiteralBool value - - literalString :: ParserExpr - literalString = do - value <- token (\case TkString x -> Just x; _ -> Nothing) (makeErrSet "string") - return $ ExLiteralString value - - variableExpr :: ParserExpr - variableExpr = ExVariable <$> identifier - - functionExpr :: ParserExpr - functionExpr = do - _ <- single TkFn - args <- - between - (single TkParenOpen) - (single TkParenClose) - ( sepBy - identifier - (single TkComma) - ) - - ExFunction args <$> functionBodyStmt - - ifElseExpr :: ParserExpr - ifElseExpr = do - _ <- single TkIf - condition <- expression - thenBody <- blockExpr - _ <- single TkElse - elseBody <- blockExpr <|> ifElseExpr - - return $ ExIfElse condition thenBody elseBody - - callExpr :: ParserExtExpr - callExpr = do - args <- - between - (single TkParenOpen) - (single TkParenClose) - (sepBy expression (single TkComma)) - return (`ExCall` args) - - curryCallExpr :: ParserExtExpr - curryCallExpr = do - args <- - between - (single TkDollarParenOpen) - (single TkParenClose) - (sepBy expression (single TkComma)) - return (`ExCurryCall` args) - - instantiationExpr :: ParserExtExpr - instantiationExpr = do - args <- - between - (single TkColonBraceOpen) - (single TkBraceClose) - (sepBy expression (single TkComma)) - return (`ExInstantiation` args) - - fieldAccessExpr :: ParserExtExpr - fieldAccessExpr = do - _ <- single TkDot - ident <- identifier - return (`ExFieldAccess` ident) \ No newline at end of file diff --git a/converter/stack.yaml b/converter/stack.yaml deleted file mode 100644 index ea7b80c..0000000 --- a/converter/stack.yaml +++ /dev/null @@ -1,120 +0,0 @@ -# This file was automatically generated by 'stack init' -# -# Some commonly used options have been documented as comments in this file. -# For advanced use and comprehensive documentation of the format, please see: -# https://docs.haskellstack.org/en/stable/yaml_configuration/ - -# Resolver to choose a 'specific' stackage snapshot or a compiler version. -# A snapshot resolver dictates the compiler version and the set of packages -# to be used for project dependencies. For example: -# -# resolver: lts-21.13 -# resolver: nightly-2023-09-24 -resolver: ghc-9.8.2 -# -# The location of a snapshot can be provided as a file or url. Stack assumes -# a snapshot provided as a file might change, whereas a url resource does not. -# -# resolver: ./custom-snapshot.yaml -# resolver: https://example.com/snapshots/2023-01-01.yaml -# resolver: -# url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/11.yaml - -# User packages to be built. -# Various formats can be used as shown in the example below. -# -# packages: -# - some-directory -# - https://example.com/foo/bar/baz-0.0.2.tar.gz -# subdirs: -# - auto-update -# - wai -packages: - - . -# Dependency packages to be pulled from upstream that are not in the resolver. -# These entries can reference officially published versions as well as -# forks / in-progress versions pinned to a git hash. For example: -# -# extra-deps: -# - acme-missiles-0.3 -# - git: https://github.com/commercialhaskell/stack.git -# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a -# -extra-deps: - - megaparsec-9.6.1 - - containers-0.7 - - binary-0.8.9.1 - - parsec-3.1.17.0 - - text-2.1.1 - - scientific-0.3.7.0 - - aeson-2.2.1.0 - - OneTuple-0.4.1.1@sha256:632dfded172086fb9f0e26d3578bcfffa3fb6d135ea5a8de17b7a33ff6e6e682,2575 - - QuickCheck-2.14.3@sha256:f03d2f404d5ba465453d0fbc1944832789a759fe7c4f9bf8616bc1378a02fde4,7847 - - case-insensitive-1.2.1.0@sha256:9dfd3171fc7698cf8d931727d3af3a7b389135b583e46b5adac1f9d2026fff61,2244 - - data-fix-0.3.2@sha256:cd7d6ff8b68aca3b51d8116870fc8ccdbc557989562cd3d5c941e4f0b7bc5af1,1734 - - dlist-1.0@sha256:55ff69d20ce638fc7727342ee67f2f868da61d3dcf3763f790bf9aa0b145e568,3812 - - generically-0.1.1@sha256:378ec049bc2853b8011df116647fbd34bb9f00edce9840e4957f98abc097597c,1169 - - hashable-1.4.4.0@sha256:ae22238274c572aa91e90c6c353e7206386708912ac5e6dc40ac61d1dcc553db,5216 - - indexed-traversable-0.1.3@sha256:911f96592752ce4ffbeda00b1155dbbfac5135c71d6755ae02c00552819a9b17,2674 - - integer-conversion-0.1.0.1@sha256:0e57a82635323f015b5d6c242bcfbbeeaa9854fe9c8058e57052254dbb24bb14,2250 - - integer-logarithms-1.0.3.1@sha256:0595a16d458c9c5caa425dc8ebbeb5d9adffb0c8daf4720c1d93dfcfc31dd690,3295 - - network-uri-2.6.4.2@sha256:6fffb57373962b5651a2db8b0af732098b3bf029a7ced76a9855615de2026588,3217 - - parser-combinators-1.3.0@sha256:8659573e0d443d573f5b53f81b81dafbdc988d282b90c11e3da73562b4ea7876,1640 - - primitive-0.9.0.0@sha256:2e08c5409e3559c7f1669ef50e9a0d9a397e68ecf51110d5e2cedf05cdd7d93c,3171 - - semialign-1.3@sha256:7be9ef5ca1d6b052991f68c053aab68b9d1ab3b1938c9557ac84c97937815223,2888 - - strict-0.5@sha256:bd57d7b3655951dfaa7d1e1374d7352dfe83f82a9c98309bf3a6587ef8cbd87d,4120 - - tagged-0.8.8@sha256:9193defbde3dda997236ccc11a1db3e073cc531fe523e13e9659df776feb0b32,2732 - - text-iso8601-0.1@sha256:ac86f2500ca751db3c0de029dd7e7826bef7366d59dc0085b00fc695c43b9f76,2407 - - text-short-0.1.5@sha256:9c73c9c9182ca69ee92ce3758f515b1c078cd167d882ccc8c46f92f68c65e190,3216 - - th-abstraction-0.6.0.0@sha256:313760d630851a0eba6bdcb1a1eb543c4c9c583072d704067fa3248a5252a8ae,2303 - - these-1.2@sha256:011e22f6891ca028f87c04ea48796696c92d593313a9c699f7ff4f9ffd7aec6e,2882 - - time-compat-1.9.6.1@sha256:17631ef01a03a6f55fbe131690f87f6dee9a1572acc99b6c06f04882470ffb52,5076 - - unordered-containers-0.2.20@sha256:746c32b23f93cb13e52309e54e82d69e4315105f9815b1fcac25a57071505cff,3921 - - uuid-types-1.0.5.1@sha256:918c8a115a0bc427cdaa4d1f51c1634bf3ac53679d0bbe039b77b9c1b62cfcbd,2660 - - vector-0.13.1.0@sha256:bc032ccfb51d775eb6f4082c5fc02f5416b0ea0d6644a60d87677a6937f2d70d,9015 - - witherable-0.4.2@sha256:cec516b35df0ff53ab0068e70a912a0ba7b65c672fbc554727183faa195ad3b8,2342 - - assoc-1.1@sha256:56d0fd1c17aaf6268e81bf19ba5afe186128d7f88126bd546d5b3151ab692652,1617 - - base-orphans-0.9.1@sha256:c4733d09f798fc4304e936924a1a7d9fc2425aefad6c46ad4592035254b46051,3220 - - indexed-traversable-instances-0.1.1.2@sha256:00d5e3e149e2bee0f7a547e0093294c306d4276e73a619abe7d8e69f7ce03c7b,2550 - - os-string-2.0.2@sha256:32fa47f8345a2c0662fb602fc42e4b674e41ec48079b68bdecb4b6f68032c24e,3259 - - random-1.2.1.2@sha256:32397de181e20ccaacf806ec70de9308cf044f089a2be37c936f3f8967bde867,6460 - - semigroupoids-6.0.0.1@sha256:47a23b451c114e65361e713e8fe36828fca3a84285325e8f444254b2ab0c43c5,7465 - - splitmix-0.1.0.5@sha256:caa9b4a92abf1496c7f6a3c0f4e357426a54880077cb9f04e260a8bfa034b77b,6596 - - th-compat-0.1.5@sha256:177148ba8407fbaaef0231b8bf8af092eddf3b2b1a682dc88df8e86b87828e96,3238 - - vector-stream-0.1.0.1@sha256:16a69e2ed71d7b35e16860fac520f94fa4da120eb973d9f8fbf0aa3a703d4a9f,1583 - - bifunctors-5.6.2@sha256:e6a6e576b9e027ca374383c2d3a43753bce42c63c72724d3a35208a982d68c0f,3201 - - comonad-5.0.8@sha256:4a4dbfbd03fb4963987710fca994e8b5624bd05a33e5f95b7581b26f8229c5e3,3631 - - contravariant-1.5.5@sha256:470ed0e040e879e2da4af1b2c8f94e199f6135852a8107858d5ae0a95365835f,3041 - - distributive-0.6.2.1@sha256:0f99f5541cca04acf89b64432b03422b6408e830a8dff30e6c4334ef1a48680c,2996 - - transformers-compat-0.7.2@sha256:044fb9955f63ee138fcebedfdcbe54afe741f2d5892a2d0bdf3a8052bd342643,5601 - - StateVar-1.2.2@sha256:3c022c00485fe165e3080d5da6b3ca9c9b02f62c5deebc584d1b3d1309ce673e,1673 -# Override default flag values for local packages and extra-deps -# flags: {} - -# Extra package databases containing global packages -# extra-package-dbs: [] - -# Control whether we use the GHC we find on the path -# system-ghc: true -# -# Require a specific version of Stack, using version ranges -# require-stack-version: -any # Default -# require-stack-version: ">=2.13" -# -# Override the architecture used by Stack, especially useful on Windows -# arch: i386 -# arch: x86_64 -# -# Extra directories used by Stack for building -# extra-include-dirs: [/path/to/dir] -# extra-lib-dirs: [/path/to/dir] -# -# Allow a newer minor version of GHC than the snapshot specifies -# compiler-check: newer-minor -allow-newer: true -allow-newer-deps: - - aeson - - scientific - - indexed-traversable - - semialign - - witherable diff --git a/converter/stack.yaml.lock b/converter/stack.yaml.lock deleted file mode 100644 index 5048ad7..0000000 --- a/converter/stack.yaml.lock +++ /dev/null @@ -1,336 +0,0 @@ -# This file was autogenerated by Stack. -# You should not edit this file by hand. -# For more information, please see the documentation at: -# https://docs.haskellstack.org/en/stable/lock_files - -packages: -- completed: - hackage: megaparsec-9.6.1@sha256:8d8f8ee5aca5d5c16aa4219afd13687ceab8be640f40ba179359f2b42a628241,3323 - pantry-tree: - sha256: ac654040a2402a733496678905ee17198bf628d75032dd025d595bd329739af8 - size: 1545 - original: - hackage: megaparsec-9.6.1 -- completed: - hackage: containers-0.7@sha256:e9b5fdcc609159410d408c47e0be13663bb0b4a42a5183b52aa0ac9c99e1dfec,2668 - pantry-tree: - sha256: 265b0a6110df990b5f9f04d21856333ed5ed66f37a4b0a0215901d831f69629b - size: 2954 - original: - hackage: containers-0.7 -- completed: - hackage: binary-0.8.9.1@sha256:81f468c1c75fd6535152ab69b2d32ac6cfcc03e345267b069abe4da56ec95801,6523 - pantry-tree: - sha256: 956ecd662408f69615977b87a92e042abcdc447b7824b8aabf5788c4393c10c5 - size: 1976 - original: - hackage: binary-0.8.9.1 -- completed: - hackage: parsec-3.1.17.0@sha256:8407cbd428d7f640a0fff8891bd2f7aca13cebe70a5e654856f8abec9a648b56,5149 - pantry-tree: - sha256: 0922d72bd7115bbb590757bd92a827021dfe745ed6c0cd22856f767bee83d91f - size: 2810 - original: - hackage: parsec-3.1.17.0 -- completed: - hackage: text-2.1.1@sha256:aa7a5a92fe430a34d24d33878323c8a010021e05e410fe98b7fac3015c88dc74,10286 - pantry-tree: - sha256: cc6bc5e5066e35cc9f2682198eb2d50b5a517cbab64b4e8ea6f64579014eb85e - size: 8413 - original: - hackage: text-2.1.1 -- completed: - hackage: scientific-0.3.7.0@sha256:909755ab19b453169ff85281323da1488407776b2360bd9f7afdd219fd306ef2,4869 - pantry-tree: - sha256: 00e74ee83063c8c5cf5c726d9ed079a7f67051f3ddd9e2ecbbe3c6ea06271061 - size: 657 - original: - hackage: scientific-0.3.7.0 -- completed: - hackage: aeson-2.2.1.0@sha256:a23a61aada8233e10573e1612c0b2efe5a1aba0d59b05dbe2f63301822f136cb,6582 - pantry-tree: - sha256: 8a50c54b9ecba80ecc3df3ea67faa4d155d6f6a6b3e342c74f3e6b0dcdc87e13 - size: 83518 - original: - hackage: aeson-2.2.1.0 -- completed: - hackage: OneTuple-0.4.1.1@sha256:632dfded172086fb9f0e26d3578bcfffa3fb6d135ea5a8de17b7a33ff6e6e682,2575 - pantry-tree: - sha256: 7bebadb3ccdaa78924ebabab963f72427cf6bb37dc7d8268c19f5da811731ffb - size: 506 - original: - hackage: OneTuple-0.4.1.1@sha256:632dfded172086fb9f0e26d3578bcfffa3fb6d135ea5a8de17b7a33ff6e6e682,2575 -- completed: - hackage: QuickCheck-2.14.3@sha256:f03d2f404d5ba465453d0fbc1944832789a759fe7c4f9bf8616bc1378a02fde4,7847 - pantry-tree: - sha256: e920d61bcc10ef2aee0cc3e2a216d05b8491564ad27c1c5e2fbbb221b00b7f8e - size: 2315 - original: - hackage: QuickCheck-2.14.3@sha256:f03d2f404d5ba465453d0fbc1944832789a759fe7c4f9bf8616bc1378a02fde4,7847 -- completed: - hackage: case-insensitive-1.2.1.0@sha256:9dfd3171fc7698cf8d931727d3af3a7b389135b583e46b5adac1f9d2026fff61,2244 - pantry-tree: - sha256: d6f175b17eacce002fc5336c17e119d989bd97f8ad9702446163c9e27c7c79b7 - size: 688 - original: - hackage: case-insensitive-1.2.1.0@sha256:9dfd3171fc7698cf8d931727d3af3a7b389135b583e46b5adac1f9d2026fff61,2244 -- completed: - hackage: data-fix-0.3.2@sha256:cd7d6ff8b68aca3b51d8116870fc8ccdbc557989562cd3d5c941e4f0b7bc5af1,1734 - pantry-tree: - sha256: 39ea2bb3ace2b61bf72e7df77948f7fccc67c70d12a11e35dd20744eec5dd0bf - size: 262 - original: - hackage: data-fix-0.3.2@sha256:cd7d6ff8b68aca3b51d8116870fc8ccdbc557989562cd3d5c941e4f0b7bc5af1,1734 -- completed: - hackage: dlist-1.0@sha256:55ff69d20ce638fc7727342ee67f2f868da61d3dcf3763f790bf9aa0b145e568,3812 - pantry-tree: - sha256: 2dc4a62f01d4f0dfda74b700478f56f560513c6adabd0b7bc5da5aa284d2df57 - size: 953 - original: - hackage: dlist-1.0@sha256:55ff69d20ce638fc7727342ee67f2f868da61d3dcf3763f790bf9aa0b145e568,3812 -- completed: - hackage: generically-0.1.1@sha256:378ec049bc2853b8011df116647fbd34bb9f00edce9840e4957f98abc097597c,1169 - pantry-tree: - sha256: 9f30503d1fe709f3849c5dd8b9751697a8db4d66105d7ba9c3b98bf4e36bb232 - size: 233 - original: - hackage: generically-0.1.1@sha256:378ec049bc2853b8011df116647fbd34bb9f00edce9840e4957f98abc097597c,1169 -- completed: - hackage: hashable-1.4.4.0@sha256:ae22238274c572aa91e90c6c353e7206386708912ac5e6dc40ac61d1dcc553db,5216 - pantry-tree: - sha256: cd91ec6f09475d2d0b2cf49565a488c21694be0d46bf29565f9258f5f41a3a84 - size: 1249 - original: - hackage: hashable-1.4.4.0@sha256:ae22238274c572aa91e90c6c353e7206386708912ac5e6dc40ac61d1dcc553db,5216 -- completed: - hackage: indexed-traversable-0.1.3@sha256:911f96592752ce4ffbeda00b1155dbbfac5135c71d6755ae02c00552819a9b17,2674 - pantry-tree: - sha256: 181cff1f160115b7ed52b9da8f4f9d10e7042821f74b23381044661120f180e6 - size: 625 - original: - hackage: indexed-traversable-0.1.3@sha256:911f96592752ce4ffbeda00b1155dbbfac5135c71d6755ae02c00552819a9b17,2674 -- completed: - hackage: integer-conversion-0.1.0.1@sha256:0e57a82635323f015b5d6c242bcfbbeeaa9854fe9c8058e57052254dbb24bb14,2250 - pantry-tree: - sha256: 5684bd08f7edbadbff77d84075b37cdf41309bd8a0dc23bcea6ffbf4497adb7f - size: 509 - original: - hackage: integer-conversion-0.1.0.1@sha256:0e57a82635323f015b5d6c242bcfbbeeaa9854fe9c8058e57052254dbb24bb14,2250 -- completed: - hackage: integer-logarithms-1.0.3.1@sha256:0595a16d458c9c5caa425dc8ebbeb5d9adffb0c8daf4720c1d93dfcfc31dd690,3295 - pantry-tree: - sha256: fbb007f314c82d96a33dda0dfb2c3fb010347809942feb08b26f47acdefcf256 - size: 865 - original: - hackage: integer-logarithms-1.0.3.1@sha256:0595a16d458c9c5caa425dc8ebbeb5d9adffb0c8daf4720c1d93dfcfc31dd690,3295 -- completed: - hackage: network-uri-2.6.4.2@sha256:6fffb57373962b5651a2db8b0af732098b3bf029a7ced76a9855615de2026588,3217 - pantry-tree: - sha256: 659f5e9fabda559f1aff6b64d04cf8adfd69bdda535c896fe90289f307a071c9 - size: 551 - original: - hackage: network-uri-2.6.4.2@sha256:6fffb57373962b5651a2db8b0af732098b3bf029a7ced76a9855615de2026588,3217 -- completed: - hackage: parser-combinators-1.3.0@sha256:8659573e0d443d573f5b53f81b81dafbdc988d282b90c11e3da73562b4ea7876,1640 - pantry-tree: - sha256: 4e23178c63f624bbe16342a9b3cfb4afdddee393ce0beec9b19cce0a0345a080 - size: 795 - original: - hackage: parser-combinators-1.3.0@sha256:8659573e0d443d573f5b53f81b81dafbdc988d282b90c11e3da73562b4ea7876,1640 -- completed: - hackage: primitive-0.9.0.0@sha256:2e08c5409e3559c7f1669ef50e9a0d9a397e68ecf51110d5e2cedf05cdd7d93c,3171 - pantry-tree: - sha256: a862f3979a8ed2ae047287de3c7376f749ee97d5a27c9c55a4c6d94ffb7d1601 - size: 1793 - original: - hackage: primitive-0.9.0.0@sha256:2e08c5409e3559c7f1669ef50e9a0d9a397e68ecf51110d5e2cedf05cdd7d93c,3171 -- completed: - hackage: semialign-1.3@sha256:7be9ef5ca1d6b052991f68c053aab68b9d1ab3b1938c9557ac84c97937815223,2888 - pantry-tree: - sha256: e5daa7e0023dabb1b21a04bf084364b94e45e81b380e950b90f51294a1990b87 - size: 537 - original: - hackage: semialign-1.3@sha256:7be9ef5ca1d6b052991f68c053aab68b9d1ab3b1938c9557ac84c97937815223,2888 -- completed: - hackage: strict-0.5@sha256:bd57d7b3655951dfaa7d1e1374d7352dfe83f82a9c98309bf3a6587ef8cbd87d,4120 - pantry-tree: - sha256: 87b874af151a91e5d723734d6e6b98d99c0b60d4835f1ff2d39d862b3fbf04c4 - size: 654 - original: - hackage: strict-0.5@sha256:bd57d7b3655951dfaa7d1e1374d7352dfe83f82a9c98309bf3a6587ef8cbd87d,4120 -- completed: - hackage: tagged-0.8.8@sha256:9193defbde3dda997236ccc11a1db3e073cc531fe523e13e9659df776feb0b32,2732 - pantry-tree: - sha256: 7b97ce7a1e02432ecbee65dad9affbe7d40489bb139f5ffbc15d903578349260 - size: 496 - original: - hackage: tagged-0.8.8@sha256:9193defbde3dda997236ccc11a1db3e073cc531fe523e13e9659df776feb0b32,2732 -- completed: - hackage: text-iso8601-0.1@sha256:ac86f2500ca751db3c0de029dd7e7826bef7366d59dc0085b00fc695c43b9f76,2407 - pantry-tree: - sha256: 2ce4c1ddd0672388ba61a8c921c05869b6bd88c4663c4d9bbf7cd9de1a607634 - size: 427 - original: - hackage: text-iso8601-0.1@sha256:ac86f2500ca751db3c0de029dd7e7826bef7366d59dc0085b00fc695c43b9f76,2407 -- completed: - hackage: text-short-0.1.5@sha256:9c73c9c9182ca69ee92ce3758f515b1c078cd167d882ccc8c46f92f68c65e190,3216 - pantry-tree: - sha256: d3dcfee9029cd3624a788a0e65f0dea588ae0446a8a75a27d6b6164b8ee0fd57 - size: 727 - original: - hackage: text-short-0.1.5@sha256:9c73c9c9182ca69ee92ce3758f515b1c078cd167d882ccc8c46f92f68c65e190,3216 -- completed: - hackage: th-abstraction-0.6.0.0@sha256:313760d630851a0eba6bdcb1a1eb543c4c9c583072d704067fa3248a5252a8ae,2303 - pantry-tree: - sha256: 041df54679b33bf581872ec8951ef11f3d3c1b047935ea17dfb0fdc06dd94aeb - size: 671 - original: - hackage: th-abstraction-0.6.0.0@sha256:313760d630851a0eba6bdcb1a1eb543c4c9c583072d704067fa3248a5252a8ae,2303 -- completed: - hackage: these-1.2@sha256:011e22f6891ca028f87c04ea48796696c92d593313a9c699f7ff4f9ffd7aec6e,2882 - pantry-tree: - sha256: 37483703ce7326c07608b06f2f741fb0f708cb06bd10ec57d87108d068046b05 - size: 351 - original: - hackage: these-1.2@sha256:011e22f6891ca028f87c04ea48796696c92d593313a9c699f7ff4f9ffd7aec6e,2882 -- completed: - hackage: time-compat-1.9.6.1@sha256:17631ef01a03a6f55fbe131690f87f6dee9a1572acc99b6c06f04882470ffb52,5076 - pantry-tree: - sha256: 28a0fbb30a163417a5c39acc191e5caceb21a5cf2b3fa976f43490a8d3742949 - size: 4113 - original: - hackage: time-compat-1.9.6.1@sha256:17631ef01a03a6f55fbe131690f87f6dee9a1572acc99b6c06f04882470ffb52,5076 -- completed: - hackage: unordered-containers-0.2.20@sha256:746c32b23f93cb13e52309e54e82d69e4315105f9815b1fcac25a57071505cff,3921 - pantry-tree: - sha256: 4594c9803b04e23566eff12ee69380e7fd995f62c182b6a997098ee939cecfce - size: 1647 - original: - hackage: unordered-containers-0.2.20@sha256:746c32b23f93cb13e52309e54e82d69e4315105f9815b1fcac25a57071505cff,3921 -- completed: - hackage: uuid-types-1.0.5.1@sha256:918c8a115a0bc427cdaa4d1f51c1634bf3ac53679d0bbe039b77b9c1b62cfcbd,2660 - pantry-tree: - sha256: 7e596d61e20750d64db542d9c662e8b59f1be0f43e869c02681e1769125b2223 - size: 480 - original: - hackage: uuid-types-1.0.5.1@sha256:918c8a115a0bc427cdaa4d1f51c1634bf3ac53679d0bbe039b77b9c1b62cfcbd,2660 -- completed: - hackage: vector-0.13.1.0@sha256:bc032ccfb51d775eb6f4082c5fc02f5416b0ea0d6644a60d87677a6937f2d70d,9015 - pantry-tree: - sha256: 02345da767b4f6f83d724b8a73d15efe3d19ea37bcae97386eaab0dbacb89a30 - size: 4093 - original: - hackage: vector-0.13.1.0@sha256:bc032ccfb51d775eb6f4082c5fc02f5416b0ea0d6644a60d87677a6937f2d70d,9015 -- completed: - hackage: witherable-0.4.2@sha256:cec516b35df0ff53ab0068e70a912a0ba7b65c672fbc554727183faa195ad3b8,2342 - pantry-tree: - sha256: 0a64b4d06cc5b28b81c001c5f9d306ca8630c206245b313b41660e210fb1edb0 - size: 384 - original: - hackage: witherable-0.4.2@sha256:cec516b35df0ff53ab0068e70a912a0ba7b65c672fbc554727183faa195ad3b8,2342 -- completed: - hackage: assoc-1.1@sha256:56d0fd1c17aaf6268e81bf19ba5afe186128d7f88126bd546d5b3151ab692652,1617 - pantry-tree: - sha256: c6d624f9056f55b8fafdad746f489f269d4f90dc28e8e42b23064884d33c5f8d - size: 290 - original: - hackage: assoc-1.1@sha256:56d0fd1c17aaf6268e81bf19ba5afe186128d7f88126bd546d5b3151ab692652,1617 -- completed: - hackage: base-orphans-0.9.1@sha256:c4733d09f798fc4304e936924a1a7d9fc2425aefad6c46ad4592035254b46051,3220 - pantry-tree: - sha256: 7675c51e8d87899f8749f3140349771c977f9ff7497e896aead1bbae9d570c74 - size: 1272 - original: - hackage: base-orphans-0.9.1@sha256:c4733d09f798fc4304e936924a1a7d9fc2425aefad6c46ad4592035254b46051,3220 -- completed: - hackage: indexed-traversable-instances-0.1.1.2@sha256:00d5e3e149e2bee0f7a547e0093294c306d4276e73a619abe7d8e69f7ce03c7b,2550 - pantry-tree: - sha256: 47cf9c6a2007db09aa40ba559f0c3ccd1341f8e68b0dfc7b410b3b815ff36ab5 - size: 366 - original: - hackage: indexed-traversable-instances-0.1.1.2@sha256:00d5e3e149e2bee0f7a547e0093294c306d4276e73a619abe7d8e69f7ce03c7b,2550 -- completed: - hackage: os-string-2.0.2@sha256:32fa47f8345a2c0662fb602fc42e4b674e41ec48079b68bdecb4b6f68032c24e,3259 - pantry-tree: - sha256: 5b1dbaf1663005907462032997264b7942befb9fc108491c1fdd5e488ac0817e - size: 2217 - original: - hackage: os-string-2.0.2@sha256:32fa47f8345a2c0662fb602fc42e4b674e41ec48079b68bdecb4b6f68032c24e,3259 -- completed: - hackage: random-1.2.1.2@sha256:32397de181e20ccaacf806ec70de9308cf044f089a2be37c936f3f8967bde867,6460 - pantry-tree: - sha256: cd0fe2b39e4d4efad4d78f69c28b7fd49ffe2879923b3a9272352edc43a956e6 - size: 1528 - original: - hackage: random-1.2.1.2@sha256:32397de181e20ccaacf806ec70de9308cf044f089a2be37c936f3f8967bde867,6460 -- completed: - hackage: semigroupoids-6.0.0.1@sha256:47a23b451c114e65361e713e8fe36828fca3a84285325e8f444254b2ab0c43c5,7465 - pantry-tree: - sha256: 1df286a998f4b26f8e6b596a571363197c55e05b0ff882ed2e6e6f315f8207e0 - size: 2404 - original: - hackage: semigroupoids-6.0.0.1@sha256:47a23b451c114e65361e713e8fe36828fca3a84285325e8f444254b2ab0c43c5,7465 -- completed: - hackage: splitmix-0.1.0.5@sha256:caa9b4a92abf1496c7f6a3c0f4e357426a54880077cb9f04e260a8bfa034b77b,6596 - pantry-tree: - sha256: 6eb34b55fb0eb1c41fe539fb8ece181e31e82f4c89abf2b1aaf46df4b274797d - size: 1519 - original: - hackage: splitmix-0.1.0.5@sha256:caa9b4a92abf1496c7f6a3c0f4e357426a54880077cb9f04e260a8bfa034b77b,6596 -- completed: - hackage: th-compat-0.1.5@sha256:177148ba8407fbaaef0231b8bf8af092eddf3b2b1a682dc88df8e86b87828e96,3238 - pantry-tree: - sha256: f4008e9df61fb03334008c7aa024f6701fc7aee7cbd1b1ac5c1e710bb2541d09 - size: 530 - original: - hackage: th-compat-0.1.5@sha256:177148ba8407fbaaef0231b8bf8af092eddf3b2b1a682dc88df8e86b87828e96,3238 -- completed: - hackage: vector-stream-0.1.0.1@sha256:16a69e2ed71d7b35e16860fac520f94fa4da120eb973d9f8fbf0aa3a703d4a9f,1583 - pantry-tree: - sha256: 972e6a2098c0784a40a65f75aa811dee861afe519872f726c695749f588b8bde - size: 325 - original: - hackage: vector-stream-0.1.0.1@sha256:16a69e2ed71d7b35e16860fac520f94fa4da120eb973d9f8fbf0aa3a703d4a9f,1583 -- completed: - hackage: bifunctors-5.6.2@sha256:e6a6e576b9e027ca374383c2d3a43753bce42c63c72724d3a35208a982d68c0f,3201 - pantry-tree: - sha256: 5d804f96ef9033c8993061ccbe211b9c9717cba5774a156f4f9aeeba249b591d - size: 1466 - original: - hackage: bifunctors-5.6.2@sha256:e6a6e576b9e027ca374383c2d3a43753bce42c63c72724d3a35208a982d68c0f,3201 -- completed: - hackage: comonad-5.0.8@sha256:4a4dbfbd03fb4963987710fca994e8b5624bd05a33e5f95b7581b26f8229c5e3,3631 - pantry-tree: - sha256: 5810cb53d6c5e73239ad6d183eab847fba8fc1a8cd09056ede5d00c8848c8c7e - size: 1618 - original: - hackage: comonad-5.0.8@sha256:4a4dbfbd03fb4963987710fca994e8b5624bd05a33e5f95b7581b26f8229c5e3,3631 -- completed: - hackage: contravariant-1.5.5@sha256:470ed0e040e879e2da4af1b2c8f94e199f6135852a8107858d5ae0a95365835f,3041 - pantry-tree: - sha256: 9eb62fea28548dc8a0f60fd47c12843092b78b24ed771b8ad63a0bb34dba8bc4 - size: 652 - original: - hackage: contravariant-1.5.5@sha256:470ed0e040e879e2da4af1b2c8f94e199f6135852a8107858d5ae0a95365835f,3041 -- completed: - hackage: distributive-0.6.2.1@sha256:0f99f5541cca04acf89b64432b03422b6408e830a8dff30e6c4334ef1a48680c,2996 - pantry-tree: - sha256: a42bed5fe0ba295643538312dee6c9436314c05a6f7efdd32b4303979f8bd744 - size: 735 - original: - hackage: distributive-0.6.2.1@sha256:0f99f5541cca04acf89b64432b03422b6408e830a8dff30e6c4334ef1a48680c,2996 -- completed: - hackage: transformers-compat-0.7.2@sha256:044fb9955f63ee138fcebedfdcbe54afe741f2d5892a2d0bdf3a8052bd342643,5601 - pantry-tree: - sha256: f49610c6a2faf82111e5d4222576f4afbcfa904bf56665232c5aa077dfc7578f - size: 1724 - original: - hackage: transformers-compat-0.7.2@sha256:044fb9955f63ee138fcebedfdcbe54afe741f2d5892a2d0bdf3a8052bd342643,5601 -- completed: - hackage: StateVar-1.2.2@sha256:3c022c00485fe165e3080d5da6b3ca9c9b02f62c5deebc584d1b3d1309ce673e,1673 - pantry-tree: - sha256: 204cac98219e99334f47b12c565945611748ea03a4d629273dd697d738bcfd7f - size: 314 - original: - hackage: StateVar-1.2.2@sha256:3c022c00485fe165e3080d5da6b3ca9c9b02f62c5deebc584d1b3d1309ce673e,1673 -snapshots: [] diff --git a/docs/src/01-getting-started/02-installation.md b/docs/src/01-getting-started/02-installation.md index 1a3ada3..ff02d34 100644 --- a/docs/src/01-getting-started/02-installation.md +++ b/docs/src/01-getting-started/02-installation.md @@ -4,18 +4,10 @@ Prebuilt executable is only available for Windows. -You can download if from [release page](https://github.com/leokostarev/frugurt-lang/releases). +You can download if from [release page](https://github.com/frugurt-lang/frugurt/releases). ## Build from source code -You can build Frugurt from [source code](https://github.com/leokostarev/frugurt-lang) on any platform. +You can build Frugurt from [source code](https://github.com/frugurt-lang/frugurt) on any platform. Use [Rust Toolchain](https://www.rust-lang.org/tools/install) to build interpreter. -Interpreter code is located in `rfruit` directory. -Building rust executable is straightforward. - -Use [Haskell Tool Stack](https://docs.haskellstack.org/en/stable/) to build the converter. -Converter code is located in `converter` directory. -Run `stack build` to build the converter. - -Place `converter.exe` in the same directory as `rfruit.exe` diff --git a/docs/src/02-common-concepts/02-variables-and-types.md b/docs/src/02-common-concepts/02-variables-and-types.md index a0a1786..8939ee7 100644 --- a/docs/src/02-common-concepts/02-variables-and-types.md +++ b/docs/src/02-common-concepts/02-variables-and-types.md @@ -54,4 +54,4 @@ let f = fn(x, y) { print(f(1, 2)); // 3 ``` -We will learn more about functions in the [corresponding chapter](https://leokostarev.github.io/frugurt-lang/02-common-concepts/05-functions.html). +We will learn more about functions in the [corresponding chapter](https://frugurt-lang.github.io/frugurt/02-common-concepts/05-functions.html). diff --git a/rfruit/src/interpreter/runner.rs b/rfruit/src/interpreter/runner.rs deleted file mode 100644 index 55e8f89..0000000 --- a/rfruit/src/interpreter/runner.rs +++ /dev/null @@ -1,61 +0,0 @@ -use std::{env::current_dir, path::Path, process::Command, rc::Rc}; - -use serde_json::Value; - -use crate::interpreter::{ast_json_parser, control::Control, error::FruError, scope::Scope}; - -pub fn execute_file(path: &Path, converter_path: Option<&Path>) -> Result, FruError> { - let converter_result = Command::new( - converter_path.unwrap_or( - current_dir() - .unwrap() - .join(Path::new("converter")) - .as_path(), - ), - ) - .arg(path) - .output() - .expect("converter should be located in the same directory"); - - let text = std::str::from_utf8(&converter_result.stdout); - - let text = match text { - Ok(text) => text, - Err(error) => return Err(FruError::new(format!("Parser error: {error}"))), - }; - - let json_ast = serde_json::from_str(text); - - let json_ast: Value = match json_ast { - Ok(json_ast) => json_ast, - Err(error) => return Err(FruError::new(format!("Serde error: {error} {text}"))), - }; - - if let Some(x) = json_ast.get("error") { - return Err(FruError::new(format!( - "Error occurred during parsing: {}\n\ - Details: {}", - x.as_str().unwrap(), - json_ast["message"].as_str().unwrap() - ))); - } - - let ast = ast_json_parser::parse(json_ast); - - let global_scope = Scope::new_global(); - - let result = ast.execute(global_scope.clone()); - - match result { - Control::Nah => {} - Control::Error(e) => return Err(e), - unexpected_signal => { - return Err(FruError::new(format!( - "Unexpected signal: {:?}", - unexpected_signal - ))) - } - } - - Ok(global_scope) -} diff --git a/rfruit/rust-toolchain.toml b/rust-toolchain.toml similarity index 100% rename from rfruit/rust-toolchain.toml rename to rust-toolchain.toml diff --git a/rfruit/src/helpers.rs b/src/helpers.rs similarity index 100% rename from rfruit/src/helpers.rs rename to src/helpers.rs diff --git a/rfruit/src/interpreter/ast_json_parser.rs b/src/interpreter/ast_json_parser.rs similarity index 100% rename from rfruit/src/interpreter/ast_json_parser.rs rename to src/interpreter/ast_json_parser.rs diff --git a/rfruit/src/interpreter/builtins/functions.rs b/src/interpreter/builtins/functions.rs similarity index 100% rename from rfruit/src/interpreter/builtins/functions.rs rename to src/interpreter/builtins/functions.rs diff --git a/rfruit/src/interpreter/builtins/mod.rs b/src/interpreter/builtins/mod.rs similarity index 100% rename from rfruit/src/interpreter/builtins/mod.rs rename to src/interpreter/builtins/mod.rs diff --git a/rfruit/src/interpreter/builtins/operators.rs b/src/interpreter/builtins/operators.rs similarity index 100% rename from rfruit/src/interpreter/builtins/operators.rs rename to src/interpreter/builtins/operators.rs diff --git a/rfruit/src/interpreter/control.rs b/src/interpreter/control.rs similarity index 100% rename from rfruit/src/interpreter/control.rs rename to src/interpreter/control.rs diff --git a/rfruit/src/interpreter/easter_eggs/mod.rs b/src/interpreter/easter_eggs/mod.rs similarity index 100% rename from rfruit/src/interpreter/easter_eggs/mod.rs rename to src/interpreter/easter_eggs/mod.rs diff --git a/rfruit/src/interpreter/error.rs b/src/interpreter/error.rs similarity index 100% rename from rfruit/src/interpreter/error.rs rename to src/interpreter/error.rs diff --git a/rfruit/src/interpreter/expression.rs b/src/interpreter/expression.rs similarity index 98% rename from rfruit/src/interpreter/expression.rs rename to src/interpreter/expression.rs index afc5ac8..4d94856 100644 --- a/rfruit/src/interpreter/expression.rs +++ b/src/interpreter/expression.rs @@ -45,8 +45,8 @@ pub enum FruExpression { }, If { condition: Box, - then_body: Rc, - else_body: Rc, + then_body: Box, + else_body: Box, }, } diff --git a/rfruit/src/interpreter/identifier.rs b/src/interpreter/identifier.rs similarity index 100% rename from rfruit/src/interpreter/identifier.rs rename to src/interpreter/identifier.rs diff --git a/rfruit/src/interpreter/mod.rs b/src/interpreter/mod.rs similarity index 75% rename from rfruit/src/interpreter/mod.rs rename to src/interpreter/mod.rs index d50e346..0fbf867 100644 --- a/rfruit/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -1,11 +1,12 @@ -pub mod ast_json_parser; +// pub mod ast_json_parser; pub mod builtins; pub mod control; +mod easter_eggs; pub mod error; pub mod expression; pub mod identifier; pub mod runner; -mod easter_eggs; pub mod scope; pub mod statement; +pub mod tree_sitter_parser; pub mod value; diff --git a/src/interpreter/runner.rs b/src/interpreter/runner.rs new file mode 100644 index 0000000..ff40c0f --- /dev/null +++ b/src/interpreter/runner.rs @@ -0,0 +1,26 @@ +use std::{path::Path, rc::Rc}; + +use crate::interpreter::{control::Control, error::FruError, scope::Scope, tree_sitter_parser}; + +pub fn execute_file(path: &Path) -> Result, FruError> { + let source_code = std::fs::read_to_string(path).unwrap(); + + let ast = tree_sitter_parser::parse(source_code); + + let global_scope = Scope::new_global(); + + let result = ast.execute(global_scope.clone()); + + match result { + Control::Nah => {} + Control::Error(e) => return Err(e), + unexpected_signal => { + return Err(FruError::new(format!( + "Unexpected signal: {:?}", + unexpected_signal + ))) + } + } + + Ok(global_scope) +} diff --git a/rfruit/src/interpreter/scope.rs b/src/interpreter/scope.rs similarity index 100% rename from rfruit/src/interpreter/scope.rs rename to src/interpreter/scope.rs diff --git a/rfruit/src/interpreter/statement.rs b/src/interpreter/statement.rs similarity index 93% rename from rfruit/src/interpreter/statement.rs rename to src/interpreter/statement.rs index 64070ca..c7b03fe 100644 --- a/rfruit/src/interpreter/statement.rs +++ b/src/interpreter/statement.rs @@ -12,6 +12,7 @@ use crate::interpreter::{ value::fru_watch::FruWatch, value::function::FruFunction, value::operator::AnyOperator, + value::fru_type::TypeType, }; #[derive(Debug, Clone)] @@ -35,9 +36,9 @@ pub enum FruStatement { value: Box, }, If { - cond: Box, + condition: Box, then_body: Box, - else_body: Box, + else_body: Option>, }, While { cond: Box, @@ -48,7 +49,7 @@ pub enum FruStatement { }, Break, Continue, - OperatorDefinition { + Operator { ident: Identifier, commutative: bool, left_ident: Identifier, @@ -57,7 +58,7 @@ pub enum FruStatement { right_type_ident: Identifier, body: Rc, }, - TypeDeclaration { + Type { type_type: TypeType, ident: Identifier, fields: Vec, @@ -68,13 +69,6 @@ pub enum FruStatement { }, } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum TypeType { - Struct, - // Class, TODO - // Data -} - impl FruStatement { pub fn execute(&self, scope: Rc) -> Control { match self { @@ -123,17 +117,19 @@ impl FruStatement { } FruStatement::If { - cond: condition, - then_body: then, - else_body: else_, + condition: cond, + then_body, + else_body, } => { - let result = condition.evaluate(scope.clone())?; + let result = cond.evaluate(scope.clone())?; if let FruValue::Bool(b) = result { if b { - then.execute(scope.clone()) - } else { + then_body.execute(scope.clone()) + } else if let Some(ref else_) = else_body { else_.execute(scope.clone()) + } else { + Control::Nah } } else { FruError::new_control(format!( @@ -159,7 +155,7 @@ impl FruStatement { } } } { - let res = body.execute(scope.clone())?; + let res = body.execute(scope.clone()); match res { Control::Nah => {} @@ -181,7 +177,7 @@ impl FruStatement { FruStatement::Break => Control::Break, FruStatement::Continue => Control::Continue, - FruStatement::OperatorDefinition { + FruStatement::Operator { ident, commutative, left_ident: left_arg, @@ -206,7 +202,7 @@ impl FruStatement { body: body.clone(), scope: scope.clone(), } - .clone(), + .clone(), ); } @@ -222,7 +218,7 @@ impl FruStatement { Control::Nah } - FruStatement::TypeDeclaration { + FruStatement::Type { type_type, ident, fields, diff --git a/src/interpreter/tree_sitter_parser.rs b/src/interpreter/tree_sitter_parser.rs new file mode 100644 index 0000000..2b46409 --- /dev/null +++ b/src/interpreter/tree_sitter_parser.rs @@ -0,0 +1,500 @@ +use std::collections::{BTreeSet, LinkedList}; +use std::rc::Rc; +use tree_sitter::Parser; +use tree_sitter_frugurt; + +use crate::interpreter::{ + value::operator::calculate_precedence, + expression::FruExpression, + identifier::Identifier, + statement::FruStatement, + value::fru_value::FruValue, + value::fru_type::FruField, +}; + +enum TypeSection { + Impl(Vec<(Identifier, Vec, Rc)>), + Static(Vec<(Identifier, Vec, Rc)>), + Constraints(Vec<(Vec, Rc)>), +} + +enum AnyField { + Normal(FruField), + Static((FruField, Option>)), +} + +pub fn parse(data: String) -> Box { + let bytes = data.as_bytes(); + + let mut parser = Parser::new(); + + parser // Todo: load grammar one time + .set_language(&tree_sitter_frugurt::language()) + .expect("Error loading Frugurt grammar"); + + let tree = parser.parse(bytes, None).unwrap(); + + let root = tree.root_node(); + + Box::new(dbg!(parse_statement(root, data.as_bytes()))) +} + +fn parse_statement(ast: tree_sitter::Node, source: &[u8]) -> FruStatement { + match ast.grammar_name() { + "source_file" => FruStatement::Block( + ast.children_by_field_name("body", &mut ast.walk()) + .map(|x| parse_statement(x, source)) + .collect(), + ), + + "block_statement" => FruStatement::Block( + ast.children_by_field_name("body", &mut ast.walk()) + .map(|x| parse_statement(x, source)) + .collect(), + ), + + "expression_statement" => FruStatement::Expression { + value: Box::new(parse_expression( + ast.child_by_field_name("value").unwrap(), + source, + )), + }, + + "let_statement" => FruStatement::Let { + ident: Identifier::new( + ast.child_by_field_name("ident") + .unwrap() + .utf8_text(source) + .unwrap(), + ), + value: Box::new(parse_expression( + ast.child_by_field_name("value").unwrap(), + source, + )), + }, + + "set_statement" => FruStatement::Set { + ident: Identifier::new( + ast.child_by_field_name("ident") + .unwrap() + .utf8_text(source) + .unwrap(), + ), + value: Box::new(parse_expression( + ast.child_by_field_name("value").unwrap(), + source, + )), + }, + + "set_field_statement" => { + let what = parse_expression( + ast.child_by_field_name("what").unwrap(), + source, + ); + + let value = parse_expression( + ast.child_by_field_name("value").unwrap(), + source, + ); + + match what { + FruExpression::FieldAccess { what, field } => FruStatement::SetField { + target: what, + field, + value: Box::new(value), + }, + + _ => panic!("set_field_statement: what is not a field access {:?}", what), + } + } + + "if_statement" => FruStatement::If { + condition: Box::new(parse_expression( + ast.child_by_field_name("condition").unwrap(), + source, + )), + then_body: Box::new(parse_statement( + ast.child_by_field_name("then_body").unwrap(), + source, + )), + else_body: ast + .child_by_field_name("else_body") + .map(|x| Box::new(parse_statement(x, source))), + }, + + "while_statement" => FruStatement::While { + cond: Box::new(parse_expression( + ast.child_by_field_name("condition").unwrap(), + source, + )), + body: Box::new(parse_statement( + ast.child_by_field_name("body").unwrap(), + source, + )), + }, + + "return_statement" => FruStatement::Return { + value: ast + .child_by_field_name("value") + .map_or(Box::new(FruExpression::Literal(FruValue::Nah)), |x| { + Box::new(parse_expression(x, source)) + }), + }, + + "break_statement" => FruStatement::Break, + "continue_statement" => FruStatement::Continue, + + "operator_statement" => FruStatement::Operator { + ident: Identifier::new( + ast.child_by_field_name("ident") + .unwrap() + .utf8_text(source) + .unwrap(), + ), + + commutative: ast.child_by_field_name("commutative").is_some(), + left_ident: Identifier::new( + ast.child_by_field_name("left_ident") + .unwrap() + .utf8_text(source) + .unwrap(), + ), + left_type_ident: Identifier::new( + ast.child_by_field_name("left_type_ident") + .unwrap() + .utf8_text(source) + .unwrap(), + ), + right_ident: Identifier::new( + ast.child_by_field_name("right_ident") + .unwrap() + .utf8_text(source) + .unwrap(), + ), + right_type_ident: Identifier::new( + ast.child_by_field_name("right_type_ident") + .unwrap() + .utf8_text(source) + .unwrap(), + ), + body: Rc::new(parse_function_body( + ast.child_by_field_name("body").unwrap(), + source, + )), + }, + + "type_statement" => { + let type_type = ast.child_by_field_name("type_type").unwrap() + .utf8_text(source).unwrap().try_into().unwrap(); + let ident = Identifier::new(ast.child_by_field_name("ident").unwrap().utf8_text(source).unwrap()); + + let mut fields = Vec::new(); + let mut static_fields = Vec::new(); + + for field in ast.children_by_field_name("fields", &mut ast.walk()) + .map(|x| parse_field(x, source)) { + match field { + AnyField::Normal(f) => fields.push(f), + AnyField::Static(f) => static_fields.push(f), + } + } + + let mut methods = Vec::new(); + let mut static_methods = Vec::new(); + let mut watches = Vec::new(); + + for section in ast.children_by_field_name("sections", &mut ast.walk()) { + match parse_section(section, source) { + TypeSection::Impl(x) => methods.extend(x), + TypeSection::Static(x) => static_methods.extend(x), + TypeSection::Constraints(x) => watches.extend(x), + } + } + + FruStatement::Type { + type_type, + ident, + fields, + static_fields, + watches, + methods, + static_methods, + } + } + + x => unimplemented!("Not a statement: {} {}", x, ast.utf8_text(source).unwrap()), + } +} + +fn parse_expression(ast: tree_sitter::Node, source: &[u8]) -> FruExpression { + match ast.grammar_name() { + "nah_literal" => FruExpression::Literal(FruValue::Nah), + + "number_literal" => FruExpression::Literal(FruValue::Number( + ast.utf8_text(source).unwrap().parse().unwrap(), + )), + + "bool_literal" => FruExpression::Literal(FruValue::Bool( + ast.utf8_text(source).unwrap().parse().unwrap(), + )), + + "string_literal" => { + let s = ast.utf8_text(source).unwrap(); + FruExpression::Literal(FruValue::String(s[1..s.len() - 1].to_string())) + } + + "variable" => FruExpression::Variable(Identifier::new( + ast.child(0).unwrap().utf8_text(source).unwrap(), + )), + + "block_expression" => FruExpression::Block { + body: ast + .children_by_field_name("body", &mut ast.walk()) + .map(|x| parse_statement(x, source)) + .collect(), + expr: Box::new(parse_expression( + ast.child_by_field_name("expr").unwrap(), + source, + )), + }, + + "call_expression" => FruExpression::Call { + what: Box::new(parse_expression( + ast.child_by_field_name("what").unwrap(), + source, + )), + args: { + ast.children_by_field_name("args", &mut ast.walk()) + .map(|x| parse_expression(x, source)) + .collect() + }, + }, + + "curry_call_expression" => FruExpression::CurryCall { + what: Box::new(parse_expression( + ast.child_by_field_name("what").unwrap(), + source, + )), + args: { + ast.children_by_field_name("args", &mut ast.walk()) + .map(|x| parse_expression(x, source)) + .collect() + }, + }, + + "binaries_expression" => { + enum Elem { + Expr(FruExpression), + BinOp { ident: Identifier, precedence: i32 }, + } + + let mut list = LinkedList::new(); + + let mut all_precedences = BTreeSet::new(); + + for i in 0..ast.named_child_count() { + if i % 2 == 0 { + list.push_back(Elem::Expr(parse_expression( + ast.named_child(i).unwrap(), + source, + ))); + } else { + let op = ast.named_child(i).unwrap().utf8_text(source).unwrap(); + let precedence = calculate_precedence(op); + + all_precedences.insert(precedence); + list.push_back(Elem::BinOp { + ident: Identifier::new(op), + precedence, + }); + } + } + + for target_precedence in all_precedences { + let mut cursor = list.cursor_front_mut(); + cursor.move_next(); + + loop { + let ident = match cursor.current() { + None => break, + Some(Elem::BinOp { precedence, ident }) + if *precedence == target_precedence => + { + *ident + } + _ => { + cursor.move_next(); + continue; + } + }; + + cursor.move_prev(); + + let left = cursor.remove_current().unwrap(); + cursor.remove_current(); + let right = cursor.remove_current().unwrap(); + + cursor.insert_before(Elem::Expr(FruExpression::Binary { + operator: ident, + left: Box::new(match left { + Elem::Expr(expr) => expr, + _ => panic!(), + }), + + right: Box::new(match right { + Elem::Expr(expr) => expr, + _ => panic!(), + }), + })); + } + } + + match list.pop_front().unwrap() { + Elem::Expr(expr) => expr, + _ => panic!(), + } + } + + "function_expression" => FruExpression::Function { + args: ast + .children_by_field_name("args", &mut ast.walk()) + .map(|x| Identifier::new(x.utf8_text(source).unwrap())) + .collect(), + body: Rc::new(parse_function_body( + ast.child_by_field_name("body").unwrap(), + source, + )), + }, + + "instantiation_expression" => FruExpression::Instantiation { + what: Box::new(parse_expression( + ast.child_by_field_name("what").unwrap(), + source, + )), + args: { + ast.children_by_field_name("args", &mut ast.walk()) + .map(|x| parse_expression(x, source)) + .collect() + }, + }, + + "field_access_expression" => FruExpression::FieldAccess { + what: Box::new(parse_expression( + ast.child_by_field_name("what").unwrap(), + source, + )), + field: Identifier::new( + ast.child_by_field_name("field") + .unwrap() + .utf8_text(source) + .unwrap(), + ), + }, + + "if_expression" => FruExpression::If { + condition: Box::new(parse_expression( + ast.child_by_field_name("condition").unwrap(), + source, + )), + + then_body: Box::new(parse_expression( + ast.child_by_field_name("then_body").unwrap(), + source, + )), + + else_body: Box::new(parse_expression( + ast.child_by_field_name("else_body").unwrap(), + source, + )), + }, + + _ => unimplemented!( + "Not an expression: {} {}", + ast.grammar_name(), + ast.utf8_text(source).unwrap() + ), + } +} + +fn parse_function_body(ast: tree_sitter::Node, source: &[u8]) -> FruStatement { + match ast.grammar_name() { + "block_statement" => parse_statement(ast, source), + "block_expression" => FruStatement::Return { + value: Box::new(parse_expression(ast, source)), + }, + _ => unimplemented!("Not a function body: {}", ast.grammar_name()), + } +} + +fn parse_field(ast: tree_sitter::Node, source: &[u8]) -> AnyField { + let is_public = ast.child_by_field_name("pub").is_some(); + let is_static = ast.child_by_field_name("static").is_some(); + let ident = Identifier::new(ast.child_by_field_name("ident").unwrap() + .utf8_text(source).unwrap()); + let type_ident = ast.child_by_field_name("type_ident") + .map(|x| Identifier::new(x.utf8_text(source).unwrap())); + let value = ast.child_by_field_name("value") + .map(|x| parse_expression(x, source)); + + if !is_static && value.is_some() { + let f = ast.child_by_field_name("value").unwrap(); + panic!("Non-static field {} at {}-{} cannot have an default value", ident, + f.start_position(), + f.end_position(), + ); + } + + let res = FruField { + is_public, + ident, + type_ident, + }; + + if is_static { + AnyField::Static((res, value.map(Box::new))) + } else { + AnyField::Normal(res) + } +} + +fn parse_section(ast: tree_sitter::Node, source: &[u8]) -> TypeSection { + match ast.grammar_name() { + "type_impl_section" => { + TypeSection::Impl( + ast.children_by_field_name("methods", &mut ast.walk()) + .map(|x| parse_method(x, source)).collect() + ) + } + "type_static_section" => { + TypeSection::Static( + ast.children_by_field_name("methods", &mut ast.walk()) + .map(|x| parse_method(x, source)).collect() + ) + } + "type_constraints_section" => { + TypeSection::Constraints( + ast.children_by_field_name("watches", &mut ast.walk()) + .map(|x| parse_watch(x, source)).collect() + ) + } + + _ => unimplemented!("Not a section: {}", ast.grammar_name()), + } +} + +fn parse_method(ast: tree_sitter::Node, source: &[u8]) -> (Identifier, Vec, Rc) { + let ident = Identifier::new(ast.child_by_field_name("ident").unwrap().utf8_text(source).unwrap()); + let args = ast.children_by_field_name("args", &mut ast.walk()) + .map(|x| Identifier::new(x.utf8_text(source).unwrap())).collect(); + let body = Rc::new(parse_function_body(ast.child_by_field_name("body").unwrap(), source)); + (ident, args, body) +} + +fn parse_watch(ast: tree_sitter::Node, source: &[u8]) -> (Vec, Rc) { + let args = ast.children_by_field_name("args", &mut ast.walk()) + .map(|x| Identifier::new(x.utf8_text(source).unwrap())).collect(); + + let body = Rc::new(parse_statement(ast.child_by_field_name("body").unwrap(), source)); + + (args, body) +} \ No newline at end of file diff --git a/rfruit/src/interpreter/value/fru_object.rs b/src/interpreter/value/fru_object.rs similarity index 99% rename from rfruit/src/interpreter/value/fru_object.rs rename to src/interpreter/value/fru_object.rs index 9255b36..0554d3e 100644 --- a/rfruit/src/interpreter/value/fru_object.rs +++ b/src/interpreter/value/fru_object.rs @@ -4,10 +4,10 @@ use crate::interpreter::{ error::FruError, identifier::Identifier, scope::Scope, - statement::TypeType, value::fru_type::FruType, value::fru_value::FruValue, value::function::{AnyFunction, FruFunction}, + value::fru_type::TypeType, }; #[derive(Clone)] diff --git a/rfruit/src/interpreter/value/fru_type.rs b/src/interpreter/value/fru_type.rs similarity index 90% rename from rfruit/src/interpreter/value/fru_type.rs rename to src/interpreter/value/fru_type.rs index 8b2df85..c40038c 100644 --- a/rfruit/src/interpreter/value/fru_type.rs +++ b/src/interpreter/value/fru_type.rs @@ -4,7 +4,6 @@ use crate::interpreter::{ error::FruError, identifier::Identifier, scope::Scope, - statement::TypeType, value::fru_object::FruObject, value::fru_value::FruValue, value::fru_watch::FruWatch, @@ -21,7 +20,8 @@ pub struct FruTypeInternal { pub ident: Identifier, pub type_type: TypeType, pub fields: Vec, - pub static_fields: RefCell>, // TODO: change for FruField? + pub static_fields: RefCell>, + // TODO: change for FruField? pub watches_by_field: HashMap>, pub watches: Vec, pub methods: HashMap, @@ -36,6 +36,13 @@ pub struct FruField { pub type_ident: Option, // useless for now } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum TypeType { + Struct, + // Class, TODO + // Data +} + impl FruType { pub fn new_value(internal: FruTypeInternal) -> FruValue { FruValue::Type(Self { @@ -123,6 +130,17 @@ impl FruType { } } +impl TryFrom<&str> for TypeType { + type Error = (); + + fn try_from(value: &str) -> Result { + match value { + "struct" => Ok(TypeType::Struct), + _ => Err(()), + } + } +} + impl PartialEq for FruType { fn eq(&self, other: &Self) -> bool { Rc::ptr_eq(&self.internal, &other.internal) diff --git a/rfruit/src/interpreter/value/fru_value.rs b/src/interpreter/value/fru_value.rs similarity index 100% rename from rfruit/src/interpreter/value/fru_value.rs rename to src/interpreter/value/fru_value.rs diff --git a/rfruit/src/interpreter/value/fru_watch.rs b/src/interpreter/value/fru_watch.rs similarity index 100% rename from rfruit/src/interpreter/value/fru_watch.rs rename to src/interpreter/value/fru_watch.rs diff --git a/rfruit/src/interpreter/value/function.rs b/src/interpreter/value/function.rs similarity index 100% rename from rfruit/src/interpreter/value/function.rs rename to src/interpreter/value/function.rs diff --git a/rfruit/src/interpreter/value/mod.rs b/src/interpreter/value/mod.rs similarity index 100% rename from rfruit/src/interpreter/value/mod.rs rename to src/interpreter/value/mod.rs diff --git a/rfruit/src/interpreter/value/native/mod.rs b/src/interpreter/value/native/mod.rs similarity index 100% rename from rfruit/src/interpreter/value/native/mod.rs rename to src/interpreter/value/native/mod.rs diff --git a/rfruit/src/interpreter/value/native/object.rs b/src/interpreter/value/native/object.rs similarity index 100% rename from rfruit/src/interpreter/value/native/object.rs rename to src/interpreter/value/native/object.rs diff --git a/rfruit/src/interpreter/value/operator.rs b/src/interpreter/value/operator.rs similarity index 100% rename from rfruit/src/interpreter/value/operator.rs rename to src/interpreter/value/operator.rs diff --git a/rfruit/src/main.rs b/src/main.rs similarity index 71% rename from rfruit/src/main.rs rename to src/main.rs index 751ae05..09558d5 100644 --- a/rfruit/src/main.rs +++ b/src/main.rs @@ -20,9 +20,6 @@ struct Args { #[clap(required = true, help = "File to execute")] filename: PathBuf, - #[clap(name = "converter", short, long, help = "Path to converter.exe")] - converter_path: Option, - #[clap(short, long, help = "Print execution time")] time: bool, } @@ -32,13 +29,7 @@ fn main() { let start = Instant::now(); - let result = execute_file( - args.filename.as_path(), - match &args.converter_path { - Some(path) => Some(path.as_path()), - None => None, - }, - ); + let result = execute_file(args.filename.as_path()); if let Err(err) = result { println!("{}", err); diff --git a/rfruit/tests/expression_tests.rs b/tests/expression_tests.rs similarity index 100% rename from rfruit/tests/expression_tests.rs rename to tests/expression_tests.rs diff --git a/rfruit/tests/function_tests.rs b/tests/function_tests.rs similarity index 100% rename from rfruit/tests/function_tests.rs rename to tests/function_tests.rs diff --git a/rfruit/tests/mod.rs b/tests/mod.rs similarity index 88% rename from rfruit/tests/mod.rs rename to tests/mod.rs index ea3408d..041be3d 100644 --- a/rfruit/tests/mod.rs +++ b/tests/mod.rs @@ -18,5 +18,5 @@ pub fn run(code: &str) { .expect("failed to write to temporary file"); file.flush().unwrap(); - execute_file(file.path(), None).expect("no errors"); + execute_file(file.path()).unwrap(); } diff --git a/rfruit/tests/oop_tests.rs b/tests/oop_tests.rs similarity index 100% rename from rfruit/tests/oop_tests.rs rename to tests/oop_tests.rs diff --git a/rfruit/tests/operators_tests.rs b/tests/operators_tests.rs similarity index 100% rename from rfruit/tests/operators_tests.rs rename to tests/operators_tests.rs diff --git a/rfruit/tests/scoping_tests.rs b/tests/scoping_tests.rs similarity index 100% rename from rfruit/tests/scoping_tests.rs rename to tests/scoping_tests.rs diff --git a/rfruit/tests/variable_tests.rs b/tests/variable_tests.rs similarity index 100% rename from rfruit/tests/variable_tests.rs rename to tests/variable_tests.rs diff --git a/rfruit/todo.md b/todo.md similarity index 87% rename from rfruit/todo.md rename to todo.md index 703d0e3..77498d9 100644 --- a/rfruit/todo.md +++ b/todo.md @@ -7,6 +7,7 @@ - add `overload` keyword for functions and methods - add trait polymorphism for native types - add class and data +- make cd for windows and linux releases # Needed fixes