Skip to content

Commit 304ad46

Browse files
committed
Reject nested export definitions at parse time
1 parent 701d834 commit 304ad46

2 files changed

Lines changed: 27 additions & 3 deletions

File tree

vibes/modules_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,17 @@ end`)
814814
if err == nil || !strings.Contains(err.Error(), "export is only supported for top-level functions") {
815815
t.Fatalf("expected top-level export parse error, got %v", err)
816816
}
817+
818+
_, err = engine.Compile(`def outer()
819+
if true
820+
export def nested()
821+
1
822+
end
823+
end
824+
end`)
825+
if err == nil || !strings.Contains(err.Error(), "export is only supported for top-level functions") {
826+
t.Fatalf("expected nested export parse error, got %v", err)
827+
}
817828
}
818829

819830
func TestRequirePrivateFunctionsAreNotInjectedAsGlobals(t *testing.T) {

vibes/parser.go

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ type parser struct {
3838
prefixFns map[TokenType]prefixParseFn
3939
infixFns map[TokenType]infixParseFn
4040

41-
insideClass bool
42-
privateNext bool
41+
insideClass bool
42+
privateNext bool
43+
statementNesting int
4344
}
4445

4546
func newParser(input string) *parser {
@@ -204,6 +205,10 @@ func (p *parser) parseFunctionStatement() Statement {
204205
p.nextToken()
205206
}
206207
body := []Statement{}
208+
p.statementNesting++
209+
defer func() {
210+
p.statementNesting--
211+
}()
207212
for p.curToken.Type != tokenEnd && p.curToken.Type != tokenEOF {
208213
stmt := p.parseStatement()
209214
if stmt != nil {
@@ -227,7 +232,7 @@ func (p *parser) parseFunctionStatement() Statement {
227232

228233
func (p *parser) parseExportStatement() Statement {
229234
pos := p.curToken.Pos
230-
if p.insideClass {
235+
if p.insideClass || p.statementNesting > 0 {
231236
p.addParseError(pos, "export is only supported for top-level functions")
232237
return nil
233238
}
@@ -323,6 +328,10 @@ func (p *parser) parseClassStatement() Statement {
323328
prevPrivate := p.privateNext
324329
p.insideClass = true
325330
p.privateNext = false
331+
p.statementNesting++
332+
defer func() {
333+
p.statementNesting--
334+
}()
326335

327336
for p.curToken.Type != tokenEnd && p.curToken.Type != tokenEOF {
328337
switch p.curToken.Type {
@@ -557,6 +566,10 @@ func (p *parser) parseBlock(stop ...TokenType) []Statement {
557566
for _, tt := range stop {
558567
stopSet[tt] = struct{}{}
559568
}
569+
p.statementNesting++
570+
defer func() {
571+
p.statementNesting--
572+
}()
560573

561574
for {
562575
if _, ok := stopSet[p.curToken.Type]; ok || p.curToken.Type == tokenEOF {

0 commit comments

Comments
 (0)