Skip to content
This repository was archived by the owner on Apr 8, 2018. It is now read-only.

Commit d67a820

Browse files
committed
Initial commit. Working scanner and partial working lexer.
Lexer currently only identify static content and any tag (treating them as variable for now).
1 parent f83347e commit d67a820

File tree

9 files changed

+836
-0
lines changed

9 files changed

+836
-0
lines changed

Diff for: Mustache.xcodeproj/project.pbxproj

+416
Large diffs are not rendered by default.

Diff for: Mustache.xcodeproj/project.xcworkspace/contents.xcworkspacedata

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: Mustache/Info.plist

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>CFBundleDevelopmentRegion</key>
6+
<string>en</string>
7+
<key>CFBundleExecutable</key>
8+
<string>$(EXECUTABLE_NAME)</string>
9+
<key>CFBundleIdentifier</key>
10+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11+
<key>CFBundleInfoDictionaryVersion</key>
12+
<string>6.0</string>
13+
<key>CFBundleName</key>
14+
<string>$(PRODUCT_NAME)</string>
15+
<key>CFBundlePackageType</key>
16+
<string>FMWK</string>
17+
<key>CFBundleShortVersionString</key>
18+
<string>1.0</string>
19+
<key>CFBundleSignature</key>
20+
<string>????</string>
21+
<key>CFBundleVersion</key>
22+
<string>$(CURRENT_PROJECT_VERSION)</string>
23+
<key>NSPrincipalClass</key>
24+
<string></string>
25+
</dict>
26+
</plist>

Diff for: Mustache/Mustache.h

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//
2+
// Mustache.h
3+
// Mustache
4+
//
5+
// Created by Stan Chang Khin Boon on 20/12/15.
6+
// Copyright © 2015 Trifia. All rights reserved.
7+
//
8+
9+
#import <UIKit/UIKit.h>
10+
11+
//! Project version number for Mustache.
12+
FOUNDATION_EXPORT double MustacheVersionNumber;
13+
14+
//! Project version string for Mustache.
15+
FOUNDATION_EXPORT const unsigned char MustacheVersionString[];
16+
17+
// In this header, you should import all the public headers of your framework using statements like #import <Mustache/PublicHeader.h>
18+
19+

Diff for: MustacheTests/Info.plist

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>CFBundleDevelopmentRegion</key>
6+
<string>en</string>
7+
<key>CFBundleExecutable</key>
8+
<string>$(EXECUTABLE_NAME)</string>
9+
<key>CFBundleIdentifier</key>
10+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11+
<key>CFBundleInfoDictionaryVersion</key>
12+
<string>6.0</string>
13+
<key>CFBundleName</key>
14+
<string>$(PRODUCT_NAME)</string>
15+
<key>CFBundlePackageType</key>
16+
<string>BNDL</string>
17+
<key>CFBundleShortVersionString</key>
18+
<string>1.0</string>
19+
<key>CFBundleSignature</key>
20+
<string>????</string>
21+
<key>CFBundleVersion</key>
22+
<string>1</string>
23+
</dict>
24+
</plist>

Diff for: MustacheTests/MustacheTests.swift

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//
2+
// MustacheTests.swift
3+
// MustacheTests
4+
//
5+
// Created by Stan Chang Khin Boon on 20/12/15.
6+
// Copyright © 2015 Trifia. All rights reserved.
7+
//
8+
9+
import XCTest
10+
@testable import Mustache
11+
12+
class MustacheTests: XCTestCase {
13+
func testExample() {
14+
var lexer = Lexer("Hello {{name}}")
15+
do {
16+
let tokens = try lexer.tokens()
17+
print(tokens)
18+
} catch {
19+
XCTFail()
20+
}
21+
}
22+
23+
func testExample2() {
24+
var lexer = Lexer("You have just won {{value}} dollars!")
25+
do {
26+
let tokens = try lexer.tokens()
27+
print(tokens)
28+
} catch {
29+
XCTFail()
30+
}
31+
}
32+
33+
func testExample3() {
34+
var lexer = Lexer("{{#in_ca}}\nWell, {{taxed_value}} dollars, after taxes.\n{{/in_ca}}")
35+
do {
36+
let tokens = try lexer.tokens()
37+
print(tokens)
38+
} catch {
39+
XCTFail()
40+
}
41+
}
42+
43+
func testExample4() {
44+
var lexer = Lexer(" * {{name}}\n * {{age}}\n * {{company}}\n * {{{company}}}")
45+
do {
46+
let tokens = try lexer.tokens()
47+
print(tokens)
48+
} catch {
49+
XCTFail()
50+
}
51+
}
52+
53+
func testPerformanceExample() {
54+
// This is an example of a performance test case.
55+
self.measureBlock {
56+
// Put the code you want to measure the time of here.
57+
}
58+
}
59+
60+
}

Diff for: Sources/Lexer.swift

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
//
2+
// Lexer.swift
3+
// Mustache
4+
//
5+
// Created by Stan Chang Khin Boon on 20/12/15.
6+
// Copyright © 2015 Trifia. All rights reserved.
7+
//
8+
9+
extension String.CharacterView : Equatable {
10+
}
11+
public func ==(lhs: String.CharacterView, rhs: String.CharacterView) -> Bool {
12+
if lhs.count == rhs.count {
13+
for (lc, rc) in zip(lhs, rhs) {
14+
if lc != rc {
15+
return false
16+
}
17+
}
18+
return true
19+
} else {
20+
return false
21+
}
22+
}
23+
24+
// The lexical analysis phase is near context free. The only exception is to implement Set Delimiter Tag which modify how the lexer find subsequent tags.
25+
struct Lexer {
26+
enum Token {
27+
// Tag Types
28+
case Variable(name: String)
29+
case SectionBegin(name: String, inverted: Bool)
30+
case SectionEnd(name: String)
31+
case Comment(value: String)
32+
case Partial(name: String)
33+
case SetDelimiter(value: String)
34+
35+
// Others
36+
case Static(value: String)
37+
}
38+
39+
struct Delimiter {
40+
let open = "{{"
41+
let close = "}}"
42+
}
43+
44+
// Context
45+
46+
/// The delimiter used to identify tag. Default to `{{` and `}}`.
47+
var delimiter = Delimiter()
48+
49+
// States
50+
51+
var scanner: Scanner
52+
var lookahead: Token?
53+
54+
init(_ data: String) {
55+
self.scanner = Scanner(string: data)
56+
}
57+
58+
/// Consume the next token from the lexer.
59+
mutating func next() throws -> Token {
60+
if let lookahead = self.lookahead {
61+
self.lookahead = nil
62+
return lookahead
63+
}
64+
65+
assert(self.scanner.hasNext())
66+
var result = self.scanner.scanUntil(self.delimiter.open.characters)
67+
68+
var nextToken: Token? = nil
69+
if let staticCharacters = result.beforeCharacters {
70+
let staticToken = Token.Static(value: String(staticCharacters))
71+
nextToken = staticToken
72+
}
73+
74+
if let openDelimiterRange = result.match {
75+
let closeResult = self.scanner.scanUntil(self.delimiter.close.characters)
76+
guard let closeDelimiterRange = closeResult.match else {
77+
throw Error.SyntaxError("No matching closing delimiter. Expecting \(self.delimiter.close)")
78+
}
79+
80+
let tagRange = openDelimiterRange.endIndex..<closeDelimiterRange.startIndex
81+
let tagToken = Token.Variable(name: String(self.scanner[tagRange]))
82+
if nextToken == nil {
83+
nextToken = tagToken
84+
} else {
85+
assert(self.lookahead == nil)
86+
self.lookahead = tagToken
87+
}
88+
} else {
89+
self.scanner.skip(&result)
90+
assert(result.consumed)
91+
}
92+
return nextToken!
93+
}
94+
95+
mutating func tokens() throws -> [Token] {
96+
var tokens = [Token]()
97+
while self.scanner.hasNext() {
98+
tokens.append(try self.next())
99+
}
100+
assert(!self.scanner.hasNext())
101+
return tokens
102+
}
103+
}

Diff for: Sources/Mustache.swift

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//
2+
// Mustache.swift
3+
// Mustache
4+
//
5+
// Created by Stan Chang Khin Boon on 20/12/15.
6+
// Copyright © 2015 Trifia. All rights reserved.
7+
//
8+
9+
/*
10+
Context: Stacked, key are look up recursively upwards (child -> parent -> grandparent)
11+
Context can be hash, lambdas, or object
12+
13+
Mustache Tags
14+
15+
- Multi???
16+
17+
- Static
18+
- just text
19+
- Variables
20+
- HTML escaped by default (double mustache {{}}), triple mustache {{{}}} or prepend with & to return unescaped HTML
21+
- Variable miss return an empty string by default, but can throw an error if configured
22+
- Sections
23+
- {{#begin}} {{/end}}
24+
- Inverted Sections
25+
- {{^begin}} {{/end}}
26+
- Comments
27+
- {{! comment }}
28+
- may contain new line
29+
- Partials
30+
- Set Delimiters
31+
*/
32+
33+
enum Error : ErrorType {
34+
case SyntaxError(String)
35+
}
36+
37+
38+
39+
// The parser

0 commit comments

Comments
 (0)