Skip to content

Instantly share code, notes, and snippets.

@kana-sama
Last active October 16, 2016 13:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kana-sama/35f1ba5ad359608b24c410d00867a77d to your computer and use it in GitHub Desktop.
Save kana-sama/35f1ba5ad359608b24c410d00867a77d to your computer and use it in GitHub Desktop.
(ns ast.core
(:require [clojure.core.match :refer [match]]
[clojure.string :refer [join]]))
(defn ast->base [ast]
(match ast
[:number n] (str n)
[:string s] (str "\"" s "\"")))
(defn ast->js [ast]
(match ast
[:operator op left right]
(let [left (ast->js left)
right (ast->js right)]
(str "(" left " " op " " right ")"))
[:function name & args]
(let [args (->> args (map ast->js) (join ", "))]
(str name "(" args ")"))
:else (ast->base ast)))
(defn ast->lisp [ast]
(match ast
[:operator op left right]
(ast->lisp [:function op left right])
[:function name & args]
(let [args (->> args (map ast->lisp) (cons name) (join " "))]
(str "(" args ")"))
:else (ast->base ast)))
; (10 * 2 - 100 / max(1, 2) * (pow(2, 10) - 10)
(def example-ast
[:operator "*"
[:operator "-"
[:operator "*"
[:number 10]
[:number 2]]
[:operator "/"
[:number 100]
[:function "max"
[:number 1]
[:number 2]]]]
[:operator "-"
[:function "pow"
[:number 2]
[:number 10]]
[:number 10]]])
(defn main []
(println (ast->js example-ast))
(println (ast->lisp example-ast)))
; (((10 * 2) - (100 / max(1, 2))) * (pow(2, 10) - 10))
; (* (- (* 10 2) (/ 100 (max 1 2))) (- (pow 2 10) 10))
import Html exposing (Html, code, text, ul, li)
import String exposing (join)
import List exposing (map)
-- Lib
type AST = Function String (List AST)
| Number Int
| String String
| Operator String AST AST
type alias Builder = AST -> String
toBase : Builder
toBase ast =
case ast of
Number n ->
(toString n)
String s ->
"\"" ++ s ++ "\""
_ -> "Unmatched field"
toJS : Builder
toJS ast =
case ast of
Operator op a b ->
(toJS a) ++ " " ++ op ++ " " ++ (toJS b)
Function name args ->
name ++ "(" ++ (args |> (map toJS) |> (join ", ")) ++ ")"
_ -> toBase ast
toLisp ast =
case ast of
Operator op a b ->
toLisp (Function op [ a, b ])
Function name args ->
"(" ++ name ++ " " ++ (args |> (map toLisp) |> (join " ")) ++ ")"
_ -> toBase ast
-- Example
exampleAST =
Function
"print"
[ String "2 * max(25, (1 + 4)!) = "
, Operator "*"
(Number 2)
(Function
"max"
[ Number 25
, Function
"factorial"
[ Operator "+" (Number 1) (Number 4) ]
]
)
]
main =
ul []
[ li [] [ codeExample toJS exampleAST ]
, li [] [ codeExample toLisp exampleAST ]
]
codeExample : Builder -> AST -> Html msg
codeExample builder ast =
code [] [ text (builder ast) ]
class ASTFunction {
constructor(name, args) {
this.name = name
this.args = args
}
toJS() {
const args = this.args
.map(arg => arg.toJS())
.join(', ')
return `${ this.name }(${ args })`
}
toLisp() {
const args = this.args
.map(arg => arg.toLisp())
.join(' ')
return `(${ this.name } ${ args })`
}
}
class ASTNumber {
constructor(value) {
this.value = value
}
toJS() {
return this.value.toString()
}
toLisp() {
return this.toJS()
}
}
class ASTString {
constructor(value) {
this.value = value
}
toJS() {
return `"${ this.value }"`
}
toLisp() {
return this.toJS()
}
}
class ASTOperator {
constructor(operator, left, right) {
this.operator = operator
this.left = left
this.right = right
}
toJS() {
return `${ this.left.toJS() } ${ this.operator } ${ this.right.toJS() }`
}
toLisp() {
return new ASTFunction(this.operator, [
this.left,
this.right,
]).toLisp()
}
}
const exampleAST = new ASTFunction("print", [
new ASTString("2 * max(25, (1 + 4)!) = "),
new ASTOperator("*",
new ASTNumber(2),
new ASTFunction("max", [
new ASTNumber(25),
new ASTFunction("factorial", [
new ASTOperator("+",
new ASTNumber(1),
new ASTNumber(4),
),
]),
]),
),
])
console.log(exampleAST.toJS())
console.log(exampleAST.toLisp())
/*
print("2 * max(25, (1 + 4)!) = ", 2 * max(25, factorial(1 + 4)))
(print "2 * max(25, (1 + 4)!) = " (* 2 (max 25 (factorial (+ 1 4)))))
*/
(ns ast.core
(:require [clojure.core.match :refer [match]]
[clojure.string :refer [join]]))
(defmulti ast->base first)
(defmethod ast->base :number [[_ n]] (str n))
(defmethod ast->base :string [[_ s]] (str "\"" s "\""))
(defmulti ast->js first)
(defmethod ast->js :default [[type val]] (ast->base [type val]))
(defmethod ast->js :operator [[_ op left right]]
(let [left (ast->js left)
right (ast->js right)]
(str "(" left " " op " " right ")")))
(defmethod ast->js :function [[_ name & args]]
(let [args (->> args (map ast->js) (join ","))]
(str name "(" args ")")))
(defmulti ast->lisp first)
(defmethod ast->lisp :default [[type val]] (ast->base [type val]))
(defmethod ast->lisp :operator [[_ op left right]] (ast->lisp [:function op left right]))
(defmethod ast->lisp :function [[_ name & args]]
(let [args (->> args (map ast->lisp) (cons name) (join " "))]
(str "(" args ")")))
; (10 * 2 - 100 / max(1, 2) * (pow(2, 10) - 10)
(def example-ast
[:operator "*"
[:operator "-"
[:operator "*"
[:number 10]
[:number 2]]
[:operator "/"
[:number 100]
[:function "max"
[:number 1]
[:number 2]]]]
[:operator "-"
[:function "pow"
[:number 2]
[:number 10]]
[:number 10]]])
(defn main []
(println (ast->js example-ast))
(println (ast->lisp example-ast)))
interface ASTNode {
toJS(): string;
toLisp(): string;
}
class ASTFunction {
name: string;
args: ASTNode[];
constructor(name: string, args: ASTNode[]) {
this.name = name;
this.args = args;
}
toJS(): string {
const args: string = this.args
.map(arg => arg.toJS())
.join(', ');
return `${this.name}(${args})`;
}
toLisp(): string {
const args: string = this.args
.map(arg => arg.toLisp())
.join(' ');
return `(${this.name} ${args})`;
}
}
class ASTNumber {
value: number;
constructor(value: number) {
this.value = value;
}
toJS(): string {
return this.value.toString();
}
toLisp(): string {
return this.toJS();
}
}
class ASTString {
value: string;
constructor(value: string) {
this.value = value;
}
toJS(): string {
return `"${this.value}"`;
}
toLisp(): string {
return this.toJS();
}
}
class ASTOperator {
operator: string;
left: ASTNode;
right: ASTNode;
constructor(operator: string, left: ASTNode, right: ASTNode) {
this.operator = operator;
this.left = left;
this.right = right;
}
toJS(): string {
return `(${this.left.toJS()} ${this.operator} ${this.right.toJS()})`;
}
toLisp(): string {
return new ASTFunction(this.operator, [
this.left,
this.right,
]).toLisp();
}
}
// (10 * 2 - 100 / max(1, 2) * (pow(2, 10) - 10)
const exampleAST: ASTNode = new ASTOperator("*",
new ASTOperator("-",
new ASTOperator("*",
new ASTNumber(10),
new ASTNumber(2),
),
new ASTOperator("/",
new ASTNumber(100),
new ASTFunction("max", [
new ASTNumber(1),
new ASTNumber(2),
]),
)
),
new ASTOperator("-",
new ASTFunction("pow", [
new ASTNumber(2),
new ASTNumber(10),
]),
new ASTNumber(10),
)
);
console.log(exampleAST.toJS());
console.log(exampleAST.toLisp());
// (((10 * 2) - (100 / max(1, 2))) * (pow(2, 10) - 10))
// (* (- (* 10 2) (/ 100 (max 1 2))) (- (pow 2 10) 10))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment