Skip to content

Commit 34d21fb

Browse files
committed
Add Playground to Git
0 parents  commit 34d21fb

File tree

19 files changed

+565
-0
lines changed

19 files changed

+565
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//: [Previous](@previous)
2+
/*:
3+
# Conclusion
4+
5+
![Alt text](complete-flow.png)
6+
7+
- Given an input
8+
*/
9+
10+
let input = "(s (s 4 5) 4)"
11+
12+
/*:
13+
- Extract an array of tokens (Lexing);
14+
*/
15+
16+
let tokens = Lexer.tokenize(input)
17+
18+
/*:
19+
- Parse the given tokens into a tree (Parsing);
20+
*/
21+
22+
var parser = Parser(tokens: tokens)
23+
let ast = try! parser.parse()
24+
25+
/*:
26+
- And walk through this tree, and compute the values contained inside a node (Interpreting);
27+
*/
28+
let result = try! Interpreter.eval(ast)
29+
30+
31+
/*:
32+
33+
### Resources
34+
35+
- https://ruslanspivak.com/lsbasi-part1/
36+
- https://www.amazon.com/Compilers-Principles-Techniques-Tools-2nd/dp/0321486811
37+
- http://llvm.org/docs/tutorial/
38+
*/
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
2+
public enum Token {
3+
case parensOpen
4+
case op(String)
5+
case number(Int)
6+
case parensClose
7+
}
8+
9+
public struct Lexer {
10+
public static func tokenize(_ input: String) -> [Token] {
11+
return input.characters.flatMap {
12+
switch $0 {
13+
case "(": return Token.parensOpen
14+
case ")": return Token.parensClose
15+
case "s": return Token.op($0.description)
16+
default:
17+
if "0"..."9" ~= $0 {
18+
return Token.number(Int($0.description)!)
19+
}
20+
}
21+
22+
return nil
23+
}
24+
}
25+
}
26+
27+
public indirect enum PrimaryExpressionNode {
28+
case number(Int)
29+
case expression(ExpressionNode)
30+
}
31+
32+
public struct ExpressionNode {
33+
public var op: String
34+
public var first: PrimaryExpressionNode
35+
public var second: PrimaryExpressionNode
36+
}
37+
38+
public enum ParsingError: Error {
39+
case unexpectedToken
40+
}
41+
public struct Parser {
42+
43+
var index = 0
44+
let tokens: [Token]
45+
46+
public init(tokens: [Token]) {
47+
self.tokens = tokens
48+
}
49+
50+
mutating func popToken() -> Token {
51+
let token = tokens[index]
52+
index += 1
53+
54+
return token
55+
}
56+
57+
mutating func peekToken() -> Token {
58+
return tokens[index]
59+
}
60+
61+
62+
mutating func parsePrimaryExpression() throws -> PrimaryExpressionNode {
63+
switch peekToken() {
64+
case .number(let n):
65+
_ = popToken() // Removing number
66+
return PrimaryExpressionNode.number(n)
67+
case .parensOpen:
68+
let expressionNode = try parseExpression()
69+
70+
return PrimaryExpressionNode.expression(expressionNode)
71+
default:
72+
throw ParsingError.unexpectedToken
73+
}
74+
}
75+
76+
mutating func parseExpression() throws -> ExpressionNode {
77+
guard case .parensOpen = popToken() else {
78+
throw ParsingError.unexpectedToken
79+
}
80+
guard case let .op(_operator) = popToken() else {
81+
throw ParsingError.unexpectedToken
82+
}
83+
84+
let firstExpression = try parsePrimaryExpression()
85+
let secondExpression = try parsePrimaryExpression()
86+
87+
guard case .parensClose = popToken() else {
88+
throw ParsingError.unexpectedToken
89+
}
90+
91+
return ExpressionNode(op: _operator, first: firstExpression, second: secondExpression)
92+
}
93+
94+
public mutating func parse() throws -> ExpressionNode {
95+
return try parseExpression()
96+
}
97+
}
98+
99+
enum InterpreterError: Error {
100+
case unknownOperator
101+
}
102+
103+
public struct Interpreter {
104+
public static func eval(_ expression: ExpressionNode) throws -> Int {
105+
let firstEval = try eval(expression.first)
106+
let secEval = try eval(expression.second)
107+
108+
if expression.op == "s" {
109+
return firstEval + secEval
110+
}
111+
112+
throw InterpreterError.unknownOperator
113+
}
114+
115+
static func eval(_ prim: PrimaryExpressionNode) throws -> Int {
116+
switch prim {
117+
case .expression(let exp):
118+
return try eval(exp)
119+
case .number(let n):
120+
return Int(n)
121+
}
122+
}
123+
124+
}
125+
126+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//: [Previous](@previous)
2+
/*:
3+
# Interpreter
4+
5+
*"In computer science, an interpreter is a computer program that directly executes, i.e. performs, instructions written in a programming or scripting language, without previously compiling them into a machine language program."* *-Wikipedia*
6+
7+
8+
## Example:
9+
`Mu`'s interpreter will walk through its A.S.T and compute a value by applying an operator to the children nodes.
10+
11+
12+
![Alt text](simple-ast.png)
13+
14+
*/
15+
enum InterpreterError: Error {
16+
case unknownOperator
17+
}
18+
19+
struct Interpreter {
20+
static func eval(_ expression: ExpressionNode) throws -> Int {
21+
let firstEval = try eval(expression.first)
22+
let secEval = try eval(expression.second)
23+
24+
if expression.op == "s" {
25+
return firstEval + secEval
26+
}
27+
28+
throw InterpreterError.unknownOperator
29+
}
30+
31+
static func eval(_ prim: PrimaryExpressionNode) throws -> Int {
32+
switch prim {
33+
case .expression(let exp):
34+
return try eval(exp)
35+
case .number(let n):
36+
return Int(n)
37+
}
38+
}
39+
40+
}
41+
42+
let input = "(s (s 5 2) 4)"
43+
let tokens = Lexer.tokenize(input)
44+
var parser = Parser(tokens: tokens)
45+
46+
let ast = try! parser.parse()
47+
try! Interpreter.eval(ast)
48+
49+
50+
//: [Next](@next)
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
public enum Token {
3+
case parensOpen
4+
case op(String)
5+
case number(Int)
6+
case parensClose
7+
}
8+
9+
public struct Lexer {
10+
public static func tokenize(_ input: String) -> [Token] {
11+
return input.characters.flatMap {
12+
switch $0 {
13+
case "(": return Token.parensOpen
14+
case ")": return Token.parensClose
15+
case "s": return Token.op($0.description)
16+
default:
17+
if "0"..."9" ~= $0 {
18+
return Token.number(Int($0.description)!)
19+
}
20+
}
21+
22+
return nil
23+
}
24+
}
25+
}
26+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
public indirect enum PrimaryExpressionNode {
2+
case number(Int)
3+
case expression(ExpressionNode)
4+
}
5+
6+
public struct ExpressionNode {
7+
public var op: String
8+
public var first: PrimaryExpressionNode
9+
public var second: PrimaryExpressionNode
10+
}
11+
12+
public enum ParsingError: Error {
13+
case unexpectedToken
14+
}
15+
public struct Parser {
16+
17+
var index = 0
18+
let tokens: [Token]
19+
20+
public init(tokens: [Token]) {
21+
self.tokens = tokens
22+
}
23+
24+
mutating func popToken() -> Token {
25+
let token = tokens[index]
26+
index += 1
27+
28+
return token
29+
}
30+
31+
mutating func peekToken() -> Token {
32+
return tokens[index]
33+
}
34+
35+
36+
mutating func parsePrimaryExpression() throws -> PrimaryExpressionNode {
37+
switch peekToken() {
38+
case .number(let n):
39+
_ = popToken() // Removing number
40+
return PrimaryExpressionNode.number(n)
41+
case .parensOpen:
42+
let expressionNode = try parseExpression()
43+
44+
return PrimaryExpressionNode.expression(expressionNode)
45+
default:
46+
throw ParsingError.unexpectedToken
47+
}
48+
}
49+
50+
mutating func parseExpression() throws -> ExpressionNode {
51+
guard case .parensOpen = popToken() else {
52+
throw ParsingError.unexpectedToken
53+
}
54+
guard case let .op(_operator) = popToken() else {
55+
throw ParsingError.unexpectedToken
56+
}
57+
58+
let firstExpression = try parsePrimaryExpression()
59+
let secondExpression = try parsePrimaryExpression()
60+
61+
guard case .parensClose = popToken() else {
62+
throw ParsingError.unexpectedToken
63+
}
64+
65+
return ExpressionNode(op: _operator, first: firstExpression, second: secondExpression)
66+
}
67+
68+
public mutating func parse() throws -> ExpressionNode {
69+
return try parseExpression()
70+
}
71+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*:
2+
# Writing Your Own Programming Language
3+
4+
You don't need a CS degree to write a programing language, you just need to understand 3 basic steps.
5+
6+
## The Language: **Mu(μ)**
7+
Mu is a minimal language, that is consisted by a postfix operator, a binary operation and one digit numbers.
8+
9+
### Examples:
10+
`(s 2 4)` or `(s (s 4 5) 4)` or `(s (s 4 5) (s 3 2))`...
11+
12+
## The Steps:
13+
* Lexer
14+
* Parser
15+
* Interpreter
16+
17+
![Alt text](flow.png)
18+
*/
19+
20+
let input = "(s (s 6 6) 6)" // Should return 18
21+
22+
//: [Lexer ->](@next)
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//: [Previous](@previous)
2+
/*:
3+
4+
# Lexer
5+
6+
*"In computer science, lexical analysis is the process of converting a sequence of characters into a sequence of tokens (strings with an identified "meaning"). A program that performs lexical analysis may be called a lexer, tokenizer,[1] or scanner (though "scanner" is also used to refer to the first stage of a lexer). Such a lexer is generally combined with a parser, which together analyze the syntax of programming languages..."* *-Wikipedia*
7+
8+
9+
## Example:
10+
![Alt text](lexer.png)
11+
12+
Because `Mu` is so small--only one character operator and numbers--you can simply iterate over the input and check each one character at the time.
13+
14+
*/
15+
16+
enum Token {
17+
case parensOpen
18+
case op(String)
19+
case number(Int)
20+
case parensClose
21+
}
22+
23+
struct Lexer {
24+
25+
static func tokenize(_ input: String) -> [Token] {
26+
return input.characters.flatMap {
27+
switch $0 {
28+
case "(": return Token.parensOpen
29+
case ")": return Token.parensClose
30+
case "s": return Token.op($0.description)
31+
default:
32+
if "0"..."9" ~= $0 {
33+
return Token.number(Int($0.description)!)
34+
}
35+
}
36+
37+
return nil
38+
}
39+
}
40+
}
41+
42+
let input = "(s (s 4 5) 4)"
43+
let tokens = Lexer.tokenize(input)
44+
45+
//: [Next](@next)
Loading

0 commit comments

Comments
 (0)