-
-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
this changes how parsing work fundamentally, it adds a carefully crafted abstraction layer over the common parsing practice BREAKING CHANGE: this is a breaking change refactor: new parse (squash 2) refactor: add EOF support (squash 3)
- Loading branch information
1 parent
266566f
commit 3a4ccf4
Showing
19 changed files
with
1,011 additions
and
459 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,78 +1,92 @@ | ||
import { Position } from 'unist' | ||
import { Block } from '../types' | ||
import { Lexer } from '../tokenize' | ||
import { Action, Handler } from '.' | ||
import { BlockBegin, BlockEnd } from '../types' | ||
|
||
export default (lexer: Lexer): Block | undefined => { | ||
const { peek, eat, substring } = lexer | ||
|
||
const begin = peek() | ||
/* | ||
* find the indentation of the block and apply it to | ||
* the rest of the block. | ||
* | ||
* The indentation of the first non-blank line is used as standard. | ||
* The following lines use the lesser one between its own | ||
* indentation and the standard. Leading and trailing blank lines | ||
* are omitted. | ||
*/ | ||
const align = (content: string) => { | ||
let indent = -1 | ||
return content | ||
.trimRight() | ||
.split('\n') | ||
.map((line) => { | ||
const _indent = line.search(/\S/) | ||
if (indent === -1) { | ||
indent = _indent | ||
} | ||
if (indent === -1) return '' | ||
return line.substring(Math.min(_indent, indent)) | ||
}) | ||
.join('\n') | ||
.trim() | ||
} | ||
|
||
if (!begin || begin.type !== 'block.begin') return undefined | ||
const block: Action = ( | ||
begin: BlockBegin, | ||
{ save, push, enter, lexer } | ||
): Handler => { | ||
save() | ||
const contentStart = begin.position.end | ||
const blockName = begin.name.toLowerCase() | ||
|
||
const block: Block = { | ||
const block = enter({ | ||
type: 'block', | ||
name: begin.name, | ||
params: begin.params, | ||
position: begin.position, | ||
value: '', | ||
attributes: {}, | ||
} | ||
// const a = push(block) | ||
// a(n) | ||
eat() | ||
let contentStart = begin.position.end | ||
const nl = eat('newline') | ||
if (nl) { | ||
contentStart = nl.position.end | ||
} | ||
eat('newline') | ||
|
||
const range: Position = { | ||
start: contentStart, | ||
end: begin.position.end, | ||
} | ||
|
||
/* | ||
* find the indentation of the block and apply it to | ||
* the rest of the block. | ||
* | ||
* The indentation of the first non-blank line is used as standard. | ||
* The following lines use the lesser one between its own | ||
* indentation and the standard. Leading and trailing blank lines | ||
* are omitted. | ||
*/ | ||
const align = (content: string) => { | ||
let indent = -1 | ||
return content | ||
.trimRight() | ||
.split('\n') | ||
.map((line) => { | ||
const _indent = line.search(/\S/) | ||
if (indent === -1) { | ||
indent = _indent | ||
} | ||
if (indent === -1) return '' | ||
return line.substring(Math.min(_indent, indent)) | ||
}) | ||
.join('\n') | ||
} | ||
children: [], | ||
}) | ||
push(lexer.eat()) | ||
|
||
const parse = (): Block | undefined => { | ||
const n = peek() | ||
if (!n || n.type === 'stars') return undefined | ||
eat() | ||
if ( | ||
n.type === 'block.end' && | ||
n.name.toLowerCase() === begin.name.toLowerCase() | ||
) { | ||
range.end = n.position.start | ||
eat('newline') | ||
block.value = align(substring(range)) | ||
block.position.end = n.position.end | ||
return block | ||
} | ||
return parse() | ||
return { | ||
name: 'block', | ||
rules: [ | ||
{ | ||
test: 'newline', | ||
action: (_, { restore }) => { | ||
return 'next' | ||
}, | ||
}, | ||
{ | ||
test: 'block.end', | ||
action: (token: BlockEnd, { exit, push, lexer }) => { | ||
const { eat } = lexer | ||
if (token.name.toLowerCase() !== blockName) return 'next' | ||
block.value = align( | ||
lexer.substring({ | ||
start: contentStart, | ||
end: token.position.start, | ||
}) | ||
) | ||
push(eat()) | ||
eat('newline') | ||
exit('block') | ||
return 'break' | ||
}, | ||
}, | ||
{ | ||
test: ['stars', 'EOF'], | ||
action: (token, { restore, lexer }) => { | ||
console.log(`>> got ${token}`) | ||
restore() | ||
lexer.modify((t) => ({ | ||
type: 'text.plain', | ||
value: lexer.substring(t.position), | ||
position: t.position, | ||
})) | ||
return 'break' | ||
}, | ||
}, | ||
{ test: /./, action: (_, { push, lexer }) => push(lexer.eat()) }, | ||
], | ||
} | ||
|
||
return parse() | ||
} | ||
|
||
export default block |
Oops, something went wrong.