diff options
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | .vscode/settings.json | 3 | ||||
| -rw-r--r-- | CHANGELOG.md | 11 | ||||
| -rw-r--r-- | LICENSE | 33 | ||||
| -rw-r--r-- | README.md | 1 | ||||
| -rw-r--r-- | Setup.hs | 2 | ||||
| -rw-r--r-- | app/Main.hs | 46 | ||||
| -rw-r--r-- | examples/spec.lisp | 81 | ||||
| -rw-r--r-- | examples/test.lisp | 6 | ||||
| -rw-r--r-- | lang.cabal | 64 | ||||
| -rw-r--r-- | package.yaml | 60 | ||||
| -rw-r--r-- | src/Lib.hs | 56 | ||||
| -rw-r--r-- | stack.yaml | 6 | ||||
| -rw-r--r-- | test/Spec.hs | 2 |
14 files changed, 373 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c368d45 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.stack-work/ +*~
\ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..01b6d4b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "haskell.manageHLS": "GHCup" +}
\ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..385f76d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog for `lang` + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to the +[Haskell Package Versioning Policy](https://pvp.haskell.org/). + +## Unreleased + +## 0.1.0.0 - YYYY-MM-DD @@ -1,3 +1,4 @@ +<<<<<<< HEAD MIT License Copyright (c) 2022 Jan T @@ -19,3 +20,35 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +======= +Copyright Author name here (c) 2022 + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of Author name here nor the names of other + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +>>>>>>> 8300f52 (Initial commit) diff --git a/README.md b/README.md new file mode 100644 index 0000000..e3527fc --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# lang diff --git a/Setup.hs b/Setup.hs new file mode 100644 index 0000000..9a994af --- /dev/null +++ b/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/app/Main.hs b/app/Main.hs new file mode 100644 index 0000000..a676a18 --- /dev/null +++ b/app/Main.hs @@ -0,0 +1,46 @@ +module Main (main) where +import System.Environment +import Control.Monad + +import Lib + +data Config = Config { + configScriptFileName :: Maybe String, + configVerboseMode :: Bool, + configShowHelp :: Bool +} + +parseArgs :: Config -> [String] -> Config +parseArgs config args = + case args of + ("-i":fileName:rest) -> parseArgs + config { configScriptFileName = Just fileName } rest + ("-v":rest) -> parseArgs + config { configVerboseMode = True } rest + ("-h":rest) -> parseArgs + config { configShowHelp = True } rest + _ -> config + +main :: IO () +main = do + args <- getArgs + let initialConfig = Config { + configScriptFileName = Nothing, + configVerboseMode = False, + configShowHelp = False + } + + let config = parseArgs initialConfig args + + when (configVerboseMode config) $ do + putStrLn $ "configScriptFileName:\t" ++ (show $ configScriptFileName config) + putStrLn $ "configVerboseMode:\t" ++ (show $ configVerboseMode config) + + when (configShowHelp config) $ do + error "TODO help" + + case (configScriptFileName config) of + Just scriptFileName -> runScriptFile scriptFileName + Nothing -> error "TODO REPL" + + return () diff --git a/examples/spec.lisp b/examples/spec.lisp new file mode 100644 index 0000000..2d870a3 --- /dev/null +++ b/examples/spec.lisp @@ -0,0 +1,81 @@ +; Language spec +; +; Dynamically and weakly typed, interpreted +; Impure functions marked with ! (convention) +; Boolean functions marked with ? (convention) +; Loops implemented with recursion +; +; Value types: +; Number -3.14 +; Symbol PI +; Boolean true +; String "foobar" +; Vector [1 2 3] +; Hash map { a 1 b 2 } +; Function (\[x y] (+ x y)) +; +; Syntax +; Function calls +; A sequence of values surrounded by parens is considered a function call +; In a function call, the first element must evaluate to a function value. +; The function will be invoked with the rest of the elements as arguments to the function. +; Function definition +; Calling the builtin variadic function '\' constructs a new function. The first argument +; must be a vector of symbols (parameter list). The rest of the arguments form the function +; body. The evaluated value of the last argument is returned as the return value of the +; function. +; +; Some builtin functions +; let (let sum2 (\[x y] (+ x y))) Evaluates second argument and stores value in environment +; \ (\[x y] + x y) +; print! (print! PI) +; if (if (lt? 10 5) +; (print "10 is less than 5") +; (print "10 is not less than 5")) +; match (match (sum2 1 1) +; 2 (do-thing) +; 3 (do-other-thing) +; (do-else)) +; head (head vec) +; tail (tail vec) +; prep (prep x xs) +; +; Functions are curried +; E.g. +; (let f1 (\[x y] (+ x y))) +; (let f2 (\[x] (\[y] (+ x y)))) +; ; f1 == f2 + +(let PI 3.14159) +(let circle-area (\[r] + (let rr (mul2 r r)) + (mul2 PI rr))) + +(let fibo (\[n] + (let fibo-1 (\[] (fibo (sub2 n 1)))) + (let fibo-2 (\[] (fibo (sub2 n 2)))) + (match n + 0 0 + 1 1 + (sum2 (fibo-1) (fibo-2))))) + +(print! (fibo 5)) +; 5 + +(let map (\[f lst] + (match lst + [] [] + (prep (f head lst) (map f (tail lst)))))) + +(print! + (map (sum2 1) [1 2 3])) +; 2 3 4 + +(let foldr (\[f accumulator lst] + (match lst + [] accumulator + (f (foldr f accumulator (tail lst)) (head lst))))) + +(print! + (foldr sum2 0 [1 2 3])) +; 6 diff --git a/examples/test.lisp b/examples/test.lisp new file mode 100644 index 0000000..a84d887 --- /dev/null +++ b/examples/test.lisp @@ -0,0 +1,6 @@ +foo ; test1 +(sum2 ; test2 + 1 + 2 ) +"string with space" +"another \n\"string\""
\ No newline at end of file diff --git a/lang.cabal b/lang.cabal new file mode 100644 index 0000000..8651bf0 --- /dev/null +++ b/lang.cabal @@ -0,0 +1,64 @@ +cabal-version: 1.12 + +-- This file has been generated from package.yaml by hpack version 0.34.4. +-- +-- see: https://github.com/sol/hpack + +name: lang +version: 0.1.0.0 +description: Please see the README on GitHub at <https://github.com/githubuser/lang#readme> +homepage: https://github.com/githubuser/lang#readme +bug-reports: https://github.com/githubuser/lang/issues +author: Author name here +maintainer: example@example.com +copyright: 2022 Author name here +license: BSD3 +license-file: LICENSE +build-type: Simple +extra-source-files: + README.md + CHANGELOG.md + +source-repository head + type: git + location: https://github.com/githubuser/lang + +library + exposed-modules: + Lib + other-modules: + Paths_lang + hs-source-dirs: + src + ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints + build-depends: + base >=4.7 && <5 + , containers + default-language: Haskell2010 + +executable lang-exe + main-is: Main.hs + other-modules: + Paths_lang + hs-source-dirs: + app + ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N + build-depends: + base >=4.7 && <5 + , containers + , lang + default-language: Haskell2010 + +test-suite lang-test + type: exitcode-stdio-1.0 + main-is: Spec.hs + other-modules: + Paths_lang + hs-source-dirs: + test + ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N + build-depends: + base >=4.7 && <5 + , containers + , lang + default-language: Haskell2010 diff --git a/package.yaml b/package.yaml new file mode 100644 index 0000000..e841945 --- /dev/null +++ b/package.yaml @@ -0,0 +1,60 @@ +name: lang +version: 0.1.0.0 +github: "githubuser/lang" +license: BSD3 +author: "Author name here" +maintainer: "example@example.com" +copyright: "2022 Author name here" + +extra-source-files: +- README.md +- CHANGELOG.md + +# Metadata used when publishing your package +# synopsis: Short description of your package +# category: Web + +# To avoid duplicated efforts in documentation and dealing with the +# complications of embedding Haddock markup inside cabal files, it is +# common to point users to the README.md file. +description: Please see the README on GitHub at <https://github.com/githubuser/lang#readme> + +dependencies: +- base >= 4.7 && < 5 +- containers + +ghc-options: +- -Wall +- -Wcompat +- -Widentities +- -Wincomplete-record-updates +- -Wincomplete-uni-patterns +- -Wmissing-export-lists +- -Wmissing-home-modules +- -Wpartial-fields +- -Wredundant-constraints + +library: + source-dirs: src + +executables: + lang-exe: + main: Main.hs + source-dirs: app + ghc-options: + - -threaded + - -rtsopts + - -with-rtsopts=-N + dependencies: + - lang + +tests: + lang-test: + main: Spec.hs + source-dirs: test + ghc-options: + - -threaded + - -rtsopts + - -with-rtsopts=-N + dependencies: + - lang diff --git a/src/Lib.hs b/src/Lib.hs new file mode 100644 index 0000000..b9ad7bb --- /dev/null +++ b/src/Lib.hs @@ -0,0 +1,56 @@ +module Lib + ( runScriptFile + ) where + +import qualified Data.Map as M +import qualified Data.Bifunctor as B +import Debug.Trace + +data AST + = ASTNumber Double + | ASTSymbol String + | ASTBoolean Bool + | ASTString String + | ASTVector [AST] + | ASTHashMap (M.Map AST AST) + | ASTFunction (AST -> AST) + +_tokenize :: [String] -> String -> String -> [String] +_tokenize acc current src = case src of + "" -> reverse current : acc + (x:xs) + | x == ';' -> + let commentDropped = dropWhile (\c -> c /= '\n') xs + in _tokenize (reverse current : acc) "" commentDropped + | x == '"' -> + let consume :: String -> (String, Int) + consume str = case str of + ('\\':'"':rest) -> B.bimap ('\"' :) (+ 2) (consume rest) + ('\\':'n':rest) -> B.bimap ('\n' :) (+ 2) (consume rest) + ('\\':'t':rest) -> B.bimap ('\t' :) (+ 2) (consume rest) + ('"':_) -> ("", 1) + (c:rest) -> B.bimap (c :) (+ 1) (consume rest) + [] -> error "Unbalanced string literal" + (string, stringLength) = consume xs + stringDropped = drop (stringLength) xs + in _tokenize (string : acc) "" stringDropped + | x `elem` [' ', '\n', '\t', '\r'] -> + _tokenize (reverse current : acc) "" xs + | x `elem` ['(', ')', '[', ']', '{', '}', '\\'] -> + _tokenize ([x] : acc) "" xs + | otherwise -> + _tokenize acc (x : current) xs + +tokenize :: String -> [String] +tokenize = filter (\t -> length t > 0) . reverse . _tokenize [] "" + +parse :: [String] -> [AST] +parse src = [] + +runScriptFile :: String -> IO () +runScriptFile fileName = do + src <- readFile fileName + let tokenized = tokenize src + putStrLn $ "tokenized:\t\t" ++ show tokenized + let parsed = parse tokenized + return () diff --git a/stack.yaml b/stack.yaml new file mode 100644 index 0000000..1e45440 --- /dev/null +++ b/stack.yaml @@ -0,0 +1,6 @@ +packages: +- . +system-ghc: true +resolver: + compiler: ghc-9.4.2 +require-stack-version: ==2.7.5 diff --git a/test/Spec.hs b/test/Spec.hs new file mode 100644 index 0000000..cd4753f --- /dev/null +++ b/test/Spec.hs @@ -0,0 +1,2 @@ +main :: IO () +main = putStrLn "Test suite not yet implemented" |
