Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

:dependencies [[org.clojure/clojure "1.11.1"]
[org.clojure/tools.cli "1.1.230"]
[org.web3j/core "4.13.0"]]
[org.web3j/core "4.13.0"]
[clansi "1.0.0"]]


:target-path "target/%s"
Expand Down
30 changes: 15 additions & 15 deletions src/elser/compiler.clj
Original file line number Diff line number Diff line change
Expand Up @@ -71,27 +71,27 @@
(doseq [[k v] sto-ns] (env/eset sto-env k v)))
sto-env))

(declare compile)
(declare compile-elser)

(defn compile-symbols
[symbols yul-env sto-env]
(cond
(symbol? symbols) (env/eget yul-env symbols)

(map? symbols) (let [k (keys symbols)
v (doall (map (fn [x] (compile x yul-env sto-env))
v (doall (map (fn [x] (compile-elser x yul-env sto-env))
(vals symbols)))]
(zipmap k v))

(seq? symbols) (mapv (fn [x] (compile x yul-env sto-env))
(seq? symbols) (mapv (fn [x] (compile-elser x yul-env sto-env))
symbols)

(vector? symbols) (mapv (fn [x] (compile x yul-env sto-env))
(vector? symbols) (mapv (fn [x] (compile-elser x yul-env sto-env))
symbols)

:else symbols))

(defn compile
(defn compile-elser
[symbols yul-env sto-env]
(cond
;; TODO: what to do wtih this case?
Expand All @@ -118,7 +118,7 @@
(format
"let %s := %s"
(first l)
(compile
(compile-elser
(nth l 1)
let-env
sto-env
Expand All @@ -130,15 +130,15 @@
;; Execute 'let' body.
(str yul-lets "\n"
(string/join "\n"
(mapv (fn [i] (compile (nth symbols i)
(mapv (fn [i] (compile-elser (nth symbols i)
let-env sto-env))
(range 2 (count symbols))))))

;; 'do' - evaluate all the elements of the list
;; (it doesn't return anything).
(= f 'do)
(let [exprs (mapv
(fn [sym] (compile
(fn [sym] (compile-elser
sym
yul-env
sto-env
Expand All @@ -150,14 +150,14 @@

;; 'invoke!' - function invocation.
(= f 'invoke!)
(compile (rest symbols) yul-env sto-env)
(compile-elser (rest symbols) yul-env sto-env)

;; 'loop' in Yul (loop [binds] (cond) (post-iter) (body))
;; in elser (loop [binds] (cond) (body) (post-iter)).
(= f 'loop)
(let [loop-env (env/env yul-env)
;; Compile bindings like 'let'.
yul-lets (compile
yul-lets (compile-elser
(list 'let (first (rest symbols)) nil)
loop-env sto-env)
[_ _ cnd body post-iter] symbols
Expand All @@ -177,15 +177,15 @@

(format "for { %s } %s { %s }\n { %s }\n"
yul-lets
(compile (second cnd) loop-env sto-env)
(compile-elser (second cnd) loop-env sto-env)
;; Execute 'step' block as 'do'.
(compile (cons 'do (rest post-iter))
(compile-elser (cons 'do (rest post-iter))
loop-env sto-env)
(compile body loop-env sto-env)))
(compile-elser body loop-env sto-env)))

(= f 'transfer*)
(let [to (compile (second symbols) yul-env sto-env)
value (compile (last symbols) yul-env sto-env)]
(let [to (compile-elser (second symbols) yul-env sto-env)
value (compile-elser (last symbols) yul-env sto-env)]
(format "pop(call(gas(),%s,%s,0,0,0,0))" to value))


Expand Down
11 changes: 7 additions & 4 deletions src/elser/errors.clj
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
(ns elser.errors
(:gen-class))
(:gen-class)
(:require [elser.printer :as printer]))

(defn err-eof-before-paren [] (throw (Exception. "elser: EOF before ')'")))
(defn err-throw [metadata]
(throw (Exception. (printer/fmt-err metadata))))

(defn unexpected-token [t] (format "Unexpected token: '%s'" t))

(defn err-unexpected-tkn [s]
(throw (Exception. (format "elser: unexpected token: %s" s))))
(defn err-eof-before-paren [] (throw (Exception. "elser: EOF before ')'")))

(defn err-unbalanced
[s]
Expand Down
9 changes: 4 additions & 5 deletions src/elser/main.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
(:gen-class)
(:require [elser.env :as env]
[elser.reader :as reader]
[elser.printer :as printer]
[elser.errors :as errs]
[elser.core :as core]
[elser.symtable :as symtable]
Expand All @@ -22,12 +21,12 @@
(doseq [[k v] core/types-ns] (env/eset types-env k v))

(defn READ
[inp]
(reader/read-str inp))
[inp src]
(reader/read-str inp src))

(defn rep
[inp]
(let [ast (READ inp)]
(let [ast (READ inp "./")]
(symtable/collect-symbols `(constructor ~ast))))

(defn repl-loop []
Expand All @@ -42,7 +41,7 @@

(defn process-file [file options]
(let [code (slurp file)
ast (READ (str "(" code ")"))]
ast (READ (str "(" code ")") file)]
(cond
(:ast options)
(do (println "Generated AST:")
Expand Down
26 changes: 24 additions & 2 deletions src/elser/printer.clj
Original file line number Diff line number Diff line change
@@ -1,13 +1,35 @@
(ns elser.printer
(:gen-class)
(:use [clojure.string :as string]))
(:require [clojure.string :as string]
[clansi]))

(defrecord ErrorMetadata [description chars path line pos])

(defn err-meta [description chars path line pos]
(ErrorMetadata. description chars path line pos))

(defn fmt-err
"Returns formatted error metadata."
[metadata]
(str
"\n"
(format "| Error: %s" (:description metadata)) "\n"
(format "| >>> %s" (:path metadata)) "\n"
(format "| L:%s %s" (:line metadata) (:chars metadata)) "\n"
))

(defn highlight [char] (clansi/style char :inverse :underline :red))

(defn highlight-char-in-ctx
[ctx char]
(string/replace ctx char (highlight char)))

(defn esc [s]
(-> s (string/replace "\\" "\\\\")
(string/replace "\"" "\\\"")
(string/replace "\n" "\\n")))

(defn print-str
(defn print-string
"Takes generated AST and prints it as a string."
([ast] (print-str ast true))
([ast r?]
Expand Down
151 changes: 106 additions & 45 deletions src/elser/reader.clj
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
(ns elser.reader
(:gen-class)
(:require [clojure.string :as string]
[elser.errors :as errs]))
[elser.errors :as errs]
[elser.printer :as printer]))

(def TOKENS-REGEX
(def tokens-regex
#"[\s,]*(~@|[\[\]{}()'`~^@]|\"(?:[\\].|[^\\\"])*\"?|;.*|[^\s\[\]{}()'\"`@,;]+)")

;----------------- TYPES -----------------
(def badstr-regex #"^\"")
(def str-regex #"^\"((?:[\\].|[^\\\"])*)\"$")
(def int-regex #"^-?[0-9]+$")
(def newline-regex #"(?:\n\s*)+")

(def BADSTR-REGEX #"^\"")
(def STR-TYPE #"^\"((?:[\\].|[^\\\"])*)\"$")
(def INT-TYPE #"^-?[0-9]+$")
(defrecord Token [char line])

;; Reader
(defn rdr [tokens]
{:tokens tokens :pos (atom 0)})
(defn rdr [tokens ctx]
{:tokens tokens :pos (atom 0) :ctx ctx})

(defn rnext
"Returns a token in the current position
Expand All @@ -31,29 +33,73 @@
(vec (rdr :tokens))
@(:pos rdr)))

(defn rback
"Returns the token at the previous position"
[rdr]
(get
(vec (rdr :tokens))
(- @(:pos rdr) 1)))

(defn get-line-ctx
"Return trimmed context string for line-number of raw-token."
[rdr raw-token]
(string/trim (get (:ctx rdr) (:line raw-token))))

(defn tokenize-with-metadata
"Return a vector with a vector of tokens with line metadata, and context map."
[in]
(let [raw-tokens (filter #(not= \; (first %))
(map first (re-seq tokens-regex in)))]
(loop [line 1
raw raw-tokens
tokens '[]
ctx '{}]

(if (= (count raw) 0) [tokens ctx]

(let [char (first raw)
newlines (re-find newline-regex char)
new-line (if newlines
(+ line (count (re-seq #"\n" newlines)))
line)]

(recur
new-line

(next raw)

(conj tokens (Token. (string/trim char) new-line))

(assoc ctx new-line
(str (get ctx new-line) char))
)

))
)
))

;; Basically, this functon is a lexer
(defn tokenize
"Tokenizes an input string and returns
a list of tokens. Executes lexical
analysis step."
[in]
(rdr
(filter (fn [x] (not= \; (first x)))
(map string/trim
(map second (re-seq TOKENS-REGEX in))))))
(let [[tokens ctx] (tokenize-with-metadata in)]
(rdr tokens ctx)))

(defn unesc [s]
(-> s (string/replace "\\\\" "\u029e")
(string/replace "\\\"" "\"")
(string/replace "\\n" "\n")
(string/replace "\u029e" "\\")))
(string/replace "\\\"" "\"")
(string/replace "\\n" "\n")
(string/replace "\u029e" "\\")))

(defn read-atom [rdr]
(let [token (rnext rdr)]
(defn read-atom [rdr src]
(let [raw (rnext rdr)
token (:char raw)]
(cond
(re-seq INT-TYPE token) (Integer/parseInt token)
(re-seq STR-TYPE token) (unesc (second (re-find STR-TYPE token)))
(re-seq BADSTR-REGEX token) (errs/err-unexpected-tkn token)
(re-seq int-regex token) (Integer/parseInt token)
(re-seq str-regex token) (unesc (second (re-find str-regex token)))
(re-seq badstr-regex token) (errs/unexpected-token token)
(= token "nil") nil
(= \: (get token 0)) (keyword (subs token 1))
(= token "true") true
Expand All @@ -62,42 +108,57 @@

(declare read-form)

(defn read-list [rdr beg end]
(assert (= beg (rnext rdr)))
(defn read-list [rdr beg end src]
(assert (= beg (:char (rnext rdr))))
(loop [lst []]
(let [token (rpeek rdr)]

(let [raw (rpeek rdr)
token (:char raw)]

(cond
(= token end) (do (rnext rdr) lst)
(nil? token) (errs/err-eof-before-paren)
:else (recur (conj lst (read-form rdr)))))))

(nil? token) (errs/err-throw
(printer/err-meta
(str "EOF before " "'" end "'")
(str beg " ... " end)
src
(:line (rback rdr))
""))

:else (recur (conj lst (read-form rdr src)))))))

(defn read-form
"Produces AST on tokenized input.
Executes syntactical analysis step."
[rdr]
(let [tkn (rpeek rdr)]
[rdr src]
(let [raw (rpeek rdr)
tkn (:char raw)]
(cond
(= tkn "'") (do (rnext rdr) (list 'quote (read-form rdr)))
(= tkn "`") (do (rnext rdr) (list 'quasiquote (read-form rdr)))
(= tkn "~") (do (rnext rdr) (list 'unquote (read-form rdr)))
(= tkn "'") (do (rnext rdr) (list 'quote (read-form rdr src)))
(= tkn "`") (do (rnext rdr) (list 'quasiquote (read-form rdr src)))
(= tkn "~") (do (rnext rdr) (list 'unquote (read-form rdr src)))

;; Permissions symbol => jump to the permissions map.
(= tkn "@") (do (rnext rdr) (list (read-form rdr)))
(= tkn "~@") (do (rnext rdr) (list 'splice-unquote (read-form rdr)))
(= tkn "^") (do (rnext rdr) (let [meta (read-form rdr)
data (read-form rdr)]
(list 'with-meta data meta)))
(= tkn ")") (errs/err-unbalanced "'( )'")
(= tkn "(") (apply list (read-list rdr "(" ")"))
(= tkn "@") (do (rnext rdr) (list (read-form rdr src)))
(= tkn "~@") (do (rnext rdr) (list 'splice-unquote (read-form rdr src)))
(= tkn "^") (do (rnext rdr) (let [meta (read-form rdr src)
data (read-form rdr src)]
(list 'with-meta data meta)))

(= tkn "}") (errs/err-unbalanced "'{ }'")
(= tkn "{") (apply hash-map (read-list rdr "{" "}"))
(= tkn ")") (errs/err-unbalanced tkn)
(= tkn "(") (apply list (read-list rdr "(" ")" src))

;; Ban these brackets.
(= tkn "]") (errs/err-unexpected-tkn tkn)
(= tkn "[") (errs/err-unexpected-tkn tkn)
(or (= tkn "]")
(= tkn "[")
(= tkn "}")
(= tkn "{")) (errs/err-throw
(printer/err-meta (errs/unexpected-token tkn)
(printer/highlight-char-in-ctx
(get-line-ctx rdr raw) tkn)
src (:line raw) ""))

:else (read-atom rdr))))
:else (read-atom rdr src))))

(defn read-str [in]
(read-form
(tokenize in)))
(defn read-str [in src] (read-form (tokenize in) src))
Loading