Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Parsing with Blocks
Search
Chris Eidhof | @chriseidhof
May 08, 2014
Technology
2
230
Parsing with Blocks
CocoaHeads Hamburg
Chris Eidhof | @chriseidhof
May 08, 2014
Tweet
Share
More Decks by Chris Eidhof | @chriseidhof
See All by Chris Eidhof | @chriseidhof
Dutch FP Day 2015
chriseidhof
2
380
Tiny Networking in Swift
chriseidhof
2
19k
Functional Swift - Brooklyn
chriseidhof
3
1.2k
Functional Swift - SF
chriseidhof
6
26k
Functional Swift
chriseidhof
6
1.3k
Functional Swift
chriseidhof
1
150
Functional Programming in Swift
chriseidhof
40
19k
Lighter View Controllers
chriseidhof
4
200
Practical Concurrent Programming
chriseidhof
4
280
Other Decks in Technology
See All in Technology
AI専用のリンターを作る #yumemi_patch
bengo4com
5
2.2k
CI/CD/IaC 久々に0から環境を作ったらこうなりました
kaz29
1
200
Should Our Project Join the CNCF? (Japanese Recap)
whywaita
PRO
0
300
KiCadでPad on Viaの基板作ってみた
iotengineer22
0
170
生成AI開発案件におけるClineの業務活用事例とTips
shinya337
0
190
Tokyo_reInforce_2025_recap_iam_access_analyzer
hiashisan
0
150
OpenHands🤲にContributeしてみた
kotauchisunsun
1
500
Yamla: Rustでつくるリアルタイム性を追求した機械学習基盤 / Yamla: A Rust-Based Machine Learning Platform Pursuing Real-Time Capabilities
lycorptech_jp
PRO
4
180
高速なプロダクト開発を実現、創業期から掲げるエンタープライズアーキテクチャ
kawauso
2
1.4k
Node-REDのFunctionノードでMCPサーバーの実装を試してみた / Node-RED × MCP 勉強会 vol.1
you
PRO
0
130
より良いプロダクトの開発を目指して - 情報を中心としたプロダクト開発 #phpcon #phpcon2025
bengo4com
1
3.2k
Fabric + Databricks 2025.6 の最新情報ピックアップ
ryomaru0825
1
160
Featured
See All Featured
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
34
5.9k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
32
2.4k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
31
1.3k
Gamification - CAS2011
davidbonilla
81
5.3k
A designer walks into a library…
pauljervisheath
207
24k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
53
2.8k
Adopting Sorbet at Scale
ufuk
77
9.4k
Building Adaptive Systems
keathley
43
2.6k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
8
810
Faster Mobile Websites
deanohume
307
31k
Into the Great Unknown - MozCon
thekraken
39
1.9k
A Modern Web Designer's Workflow
chriscoyier
694
190k
Transcript
Parsing with Blocks CocoaHeads Hamburg Chris Eidhof
Warning All of this is a bit crazy
Building languages is magical
stylesheet { multiplier = if(slide.onlyHeader, 2, 1), baseFontSize = 45
* multiplier, splitBaseFontSize = 25, backgroundColor = colorScheme.backgroundColor, bodyFont = { family = "Apercu", color = colorScheme.textColor, size = baseFontSize } }
DSLs → SQL → AutoLayout → NSPredicate → Regular Expressions
→ ActiveRecord
DSLs External vs. Internal
DSLs: External → SQL → CSS → NSPredicate format syntax
DSLs: Internal [view1 mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(superview.mas_top).with.offset(padding.top); make.left.equalTo(superview.mas_left).with.offset(padding.left); make.bottom.equalTo(superview.mas_bottom).with.offset(-padding.bottom); make.right.equalTo(superview.mas_right).with.offset(-padding.right);
}] Source: Masonry
V:[topField]-10-[bottomField] [flexibleButton(>=70,<=100)] |-[find]-[findNext]-[findField(>=20)]-|
None
Building an external DSL
None
Parsing 1. String → Stream of tokens 2. Stream of
tokens → Syntax Tree 3. Interpret Syntax Tree
Existing approaches → Hand-rolled parsers → Parser generators → ParseKit
/ CoreParse
An alternative approach → Based on functional programming → Backtracking
→ Immutable objects
The language
1 + 2 * 3 Expr ← Sum Sum ←
Product '+' Product Product ← Atom '*' Atom Atom ← Number
1 + 2 * 3 Expr ← Sum Sum ←
Product '+' Product | Product Product ← Atom '*' Atom | Atom Atom ← Number
(1 + 2) * 3
(1 + 2) * 3 Expr ← Sum Sum ←
Product '+' Product | Product Product ← Atom '*' Atom | Atom Atom ← Number | '(' Expr ')'
Block Syntax returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...}; Source: http://goshdarnblocksyntax.com
Live Coding
A stylesheet language
stylesheet { multiplier = if(slide.onlyHeader, 2, 1), baseFontSize = 45
* multiplier, splitBaseFontSize = 25, backgroundColor = colorScheme.backgroundColor, bodyFont = { family = "Apercu", color = colorScheme.textColor, size = baseFontSize } }
Rule stylesheet = ^(State *p) { __block NSArray *functions =
nil; return p.identifier().token(@"{"). manySepBy(method, comma).bind(to(functions)). token(@"}").yield(^id { return [[StylesheetObject alloc] initWithFunctions:functions]; }); };
Rule method = ^(State * p) { __block NSString* name
= nil; __block id body= nil; __block NSArray *parameters = nil; return p.identifier().bind(to(name)). optional(parameterList).bind(to(parameters)). token(@"="). rule(self.expression).bind(to(body)). yield(^id { return [[StylesheetFunction alloc] initWithName:name body:body parameters:parameters]; }); };
Rule mulExpression = infix(@"*", infix(@"/", functionCallExpression)); Rule addExpression = infix(@"+",
infix(@"-", mulExpression));
API
typedef State *(^Rule)(State *p);
@interface State : NSObject @property (nonatomic, strong) id result; @property
(nonatomic) BOOL failed; @property (nonatomic) NSString *errorMessage; @property (nonatomic) State *(^token)(NSString *); @property (nonatomic) State *(^identifier)(); @property (nonatomic) State *(^yield)(id (^)()); @property (nonatomic) State *(^bind)(void(^)(id result)); @property (nonatomic) State *(^oneOf)(NSArray *); @property (nonatomic) State *(^optional)(Rule); @property (nonatomic) State *(^eof)(); @property (nonatomic) State *(^rule)(Rule); @end
State Internals @interface State () @property (nonatomic) NSArray *tokens; @property
(nonatomic) NSUInteger tokenIndex; @end
self.token = ^(NSString* token) { if (self.failed) return self; NSString*
peek = self.peek; if ([token isEqual:peek]) { return [self next:peek]; } else { NSString* msg = [NSString stringWithFormat:@"Expected '%@', saw '%@'", token, peek]; return [self fail:msg]; } };
- (State *)next:(id)result { if (self.failed) return self; State *next
= [self copy]; next.failed = NO; next.result = result; next.tokenIndex++; return next; }
We created two DSLs → One for parsing (embedded) →
One external https://github.com/chriseidhof/parsingwithblocks
Thanks → @chriseidhof → http://www.objc.io → http://www.uikonf.com → http://www.decksetapp.com