Skip to content

Commit

Permalink
refactor(compiler): revert back to try/catch errors, implement statef…
Browse files Browse the repository at this point in the history
…ul lexer
  • Loading branch information
minenwerfer committed Jan 12, 2025
1 parent fa7569f commit d1008aa
Show file tree
Hide file tree
Showing 8 changed files with 297 additions and 456 deletions.
4 changes: 3 additions & 1 deletion packages/compiler/src/ast.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Property, AccessCondition } from '@aeriajs/types'
import type { Property, AccessCondition, CollectionActions, Description } from '@aeriajs/types'

export const PropertyType = {
str: 'string',
Expand Down Expand Up @@ -38,6 +38,8 @@ export type CollectionNode = {
name: string
extends?: ExportSymbol
owned?: boolean
actions?: CollectionActions
individualActions?: CollectionActions
properties: Record<string, PropertyNode>
functions?: Record<string, {
accessCondition: AccessCondition,
Expand Down
2 changes: 1 addition & 1 deletion packages/compiler/src/diagnostic.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Location } from './lexer'
import type { Location } from './token.js'

export type Diagnostic = {
message: string
Expand Down
19 changes: 11 additions & 8 deletions packages/compiler/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Result } from '@aeriajs/types'
import { tokenize } from './lexer.js'
import { parse } from './parser'
// import { generateCode } from './codegen'
import { parse } from './parser.js'
// import { generateCode } from './codegen.js'
import { analyze } from './semantic.js'

export const compile = async (input: string) => {
Expand All @@ -10,13 +10,15 @@ export const compile = async (input: string) => {
return Result.error(tokenizeError)
}

const { error, result: ast } = parse(Array.from(tokens))
if( error ) {
return Result.error(error)
}
const ast = parse(Array.from(tokens))

const r = await analyze(ast)
console.log(r)
console.log(JSON.stringify(ast, null, 2))
// if( error ) {
// return Result.error(error)
// }
//
// const r = await analyze(ast)
// console.log(r)

// return generateCode(ast)
}
Expand Down Expand Up @@ -53,6 +55,7 @@ collection Animal {
@include(Writable)
custom @expose
}
actions {}
}
collection Pet {
Expand Down
121 changes: 64 additions & 57 deletions packages/compiler/src/lexer.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,8 @@
import type { Diagnostic } from './diagnostic'
import { Result } from '@aeriajs/types'
import { TokenType, type Token, type Location } from './token.js'

export enum TokenType {
LineBreak = 'LINE_BREAK',
Comment = 'COMMENT',
LeftBracket = 'LEFT_BRACKET',
RightBracket = 'RIGHT_BRACKET',
LeftParens = 'LEFT_PARENS',
RightParens = 'RIGHT_PARENS',
LeftSquareBracket = 'LEFT_SQUARE_BRACKET',
RightSquareBracket = 'RIGHT_SQUARE_BRACKET',
Pipe = 'PIPE',
Comma = 'COMMA',
Dot = 'DOT',
Number = 'NUMBER',
Boolean = 'BOOLEAN',
Keyword = 'KEYWORD',
Identifier = 'IDENTIFIER',
QuotedString = 'QUOTED_STRING',
AttributeName = 'ATTRIBUTE_NAME',
}

export type TypeMap = {
[TokenType.Number]: number
[TokenType.Boolean]: boolean
}

export type TokenConfig = {
type TokenConfig = {
type:
| TokenType
| null
Expand All @@ -36,21 +12,12 @@ export type TokenConfig = {
| string[]
valueExtractor?: (value: string) => string
construct?: (value: string) => Token['value']
condition?: (state: LexerState) => boolean
}

export type Location = {
index: number
line: number
start: number
end: number
}

export type Token<TTokenType extends TokenType = TokenType> = {
type: TTokenType
location: Location
value: TTokenType extends keyof TypeMap
? TypeMap[TTokenType]
: string
type LexerState = {
lastToken: Token | null
inProperties: boolean
}

const TOKENS: TokenConfig[] = [
Expand Down Expand Up @@ -118,17 +85,21 @@ const TOKENS: TokenConfig[] = [
{
type: TokenType.Keyword,
matcher: [
'actions',
'collection',
'contract',
'extends',
'functions',
'functionset',
'individualActions',
'owned',
'payload',
'properties',
'query',
'response',
'name',
],
condition: (state) => !state.inProperties,
},
{
type: TokenType.Identifier,
Expand All @@ -147,15 +118,29 @@ const TOKENS: TokenConfig[] = [
]

export const tokenize = function (input: string): Result.Either<Diagnostic,Token[]> {
let index = 0
let line = 1
let start = 0
let end = 0
let
index = 0,
line = 1,
start = 0,
end = 0

const tokens: Token[] = []
const state: LexerState = {
lastToken: null,
inProperties: false,
}

while( index < input.length ) {
let hasMatch = false
for( const { type, matcher, valueExtractor, construct } of TOKENS ) {
for( const { type, matcher, valueExtractor, construct, condition } of TOKENS ) {
let value: string | undefined
let token: Token

if( condition ) {
if( !condition(state) ) {
continue
}
}

if( typeof matcher === 'string' ) {
if( input.slice(index).startsWith(matcher) ) {
Expand All @@ -164,6 +149,7 @@ export const tokenize = function (input: string): Result.Either<Diagnostic,Token
} else if( matcher instanceof RegExp ) {
const currentMatcher = new RegExp(matcher.source, 'y')
currentMatcher.lastIndex = index

const matched = currentMatcher.exec(input)
if( matched ) {
[value] = matched
Expand All @@ -175,12 +161,14 @@ export const tokenize = function (input: string): Result.Either<Diagnostic,Token
}
}
if( value ) {
let tokenValue: Token['value'] | undefined
const location: Location = {
index: index += value.length,
line,
end: end += value.length,
start: start = end - value.length,
}

switch( type ) {
case null: break
case TokenType.LineBreak:
Expand All @@ -194,22 +182,41 @@ export const tokenize = function (input: string): Result.Either<Diagnostic,Token
}
default: {
if( valueExtractor ) {
tokens.push({
type,
location,
value: construct
? construct(valueExtractor(value))
: valueExtractor(value),
})
continue
tokenValue = construct
? construct(valueExtractor(value))
: valueExtractor(value)
} else {
tokenValue = construct
? construct(value)
: value
}
tokens.push({

token = {
type,
location,
value: construct
? construct(value)
: value,
})
value: tokenValue,
}

switch( type ) {
case TokenType.LeftBracket: {
if( state.lastToken ) switch( state.lastToken.value ) {
case 'properties': {
state.inProperties = true
break
}
default: {
state.inProperties = false
}
}
break
}
case TokenType.RightBracket: {
state.inProperties = false
break
}
}

tokens.push(state.lastToken = token)
}
}

Expand Down
Loading

0 comments on commit d1008aa

Please sign in to comment.