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
業務自動化プラットフォーム Google Agentspace に入門してみる #devio2025
maroon1st
0
190
Optuna DashboardにおけるPLaMo2連携機能の紹介 / PFN LLM セミナー
pfn
PRO
1
870
LLMアプリケーション開発におけるセキュリティリスクと対策 / LLM Application Security
flatt_security
7
1.8k
Geospatialの世界最前線を探る [2025年版]
dayjournal
3
490
生成AIとM5Stack / M5 Japan Tour 2025 Autumn 東京
you
PRO
0
200
「Verify with Wallet API」を アプリに導入するために
hinakko
1
230
Oracle Cloud Infrastructure:2025年9月度サービス・アップデート
oracle4engineer
PRO
0
390
Pythonによる契約プログラミング入門 / PyCon JP 2025
7pairs
5
2.5k
Sidekiq その前に:Webアプリケーションにおける非同期ジョブ設計原則
morihirok
17
7.3k
動画データのポテンシャルを引き出す! Databricks と AI活用への奮闘記(現在進行形)
databricksjapan
0
140
SwiftUIのGeometryReaderとScrollViewを基礎から応用まで学び直す:設計と活用事例
fumiyasac0921
0
140
BtoBプロダクト開発の深層
16bitidol
0
250
Featured
See All Featured
Designing Experiences People Love
moore
142
24k
Embracing the Ebb and Flow
colly
88
4.8k
Imperfection Machines: The Place of Print at Facebook
scottboms
269
13k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
358
30k
Measuring & Analyzing Core Web Vitals
bluesmoon
9
610
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
16k
GraphQLの誤解/rethinking-graphql
sonatard
73
11k
Java REST API Framework Comparison - PWX 2021
mraible
33
8.8k
Balancing Empowerment & Direction
lara
4
680
Designing for Performance
lara
610
69k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
36
2.5k
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