Last active
October 16, 2016 13:59
-
-
Save kana-sama/35f1ba5ad359608b24c410d00867a77d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) ] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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))))) | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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