aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Tuomi <jan.tuomi@valuemotive.com>2022-09-22 22:29:38 +0300
committerJan Tuomi <jans.tuomi@gmail.com>2022-12-05 14:21:51 +0200
commit12ac2354ffca7a221cb4535354eb86907bfceea7 (patch)
treee91d72e94313b3efb36e08cfa1b8eaff77a4ba86
parent1ce7af69533658ec88971a1c53eb4a158bb66e48 (diff)
Initial commit
-rw-r--r--.gitignore2
-rw-r--r--.vscode/settings.json3
-rw-r--r--CHANGELOG.md11
-rw-r--r--LICENSE33
-rw-r--r--README.md1
-rw-r--r--Setup.hs2
-rw-r--r--app/Main.hs46
-rw-r--r--examples/spec.lisp81
-rw-r--r--examples/test.lisp6
-rw-r--r--lang.cabal64
-rw-r--r--package.yaml60
-rw-r--r--src/Lib.hs56
-rw-r--r--stack.yaml6
-rw-r--r--test/Spec.hs2
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
diff --git a/LICENSE b/LICENSE
index 2755a7d..871d842 100644
--- a/LICENSE
+++ b/LICENSE
@@ -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"