Skip to content

Instantly share code, notes, and snippets.

@Zxilly
Created August 20, 2024 15:10
Show Gist options
  • Save Zxilly/9322345ffa72594ac96697ae30fa2fdd to your computer and use it in GitHub Desktop.
Save Zxilly/9322345ffa72594ac96697ae30fa2fdd to your computer and use it in GitHub Desktop.
Broken parser
macro package json_cj
import std.ast.*
public import json_cj.helper.castJsonValue
enum JsonState {
| Initial
| ObjectStart
| ObjectKey
| ObjectColon
| ObjectValue
| ObjectComma
| ArrayStart
| ArrayValue
| ArrayComma
| PartEnd
| String
| Number
| Boolean
| Null
| End
}
// INITIAL -> OBJECT_START | ARRAY_START | STRING | NUMBER | BOOLEAN | NULL
// OBJECT_START -> OBJECT_KEY | OBJECT_END
// OBJECT_KEY -> OBJECT_COLON
// OBJECT_COLON -> OBJECT_VALUE
// OBJECT_VALUE -> OBJECT_COMMA | OBJECT_END
// OBJECT_COMMA -> OBJECT_KEY
// ARRAY_START -> ARRAY_VALUE | ARRAY_END
// ARRAY_VALUE -> ARRAY_COMMA | ARRAY_END
// ARRAY_COMMA -> ARRAY_VALUE
// STRING | NUMBER | BOOLEAN | NULL -> OBJECT_COMMA | OBJECT_END | ARRAY_COMMA | ARRAY_END | END
public macro Json(t: Tokens): Tokens {
var objCnt = 0
func getObjName(): String {
return "jo${objCnt++}"
}
func getArrayName(): String {
return "ja${objCnt++}"
}
func getIdent(s: String): Token {
return Token(TokenKind.IDENTIFIER, s)
}
var ret = Tokens()
var state = JsonState.Initial
var tIndex = 0
var stack = Stack<String>()
var pendingKey = None<String>
func partEnd() {
state = JsonState.PartEnd
var id = getIdent(stack.pop())
if (stack.isEmpty()) {
ret.append(quote(
return $(id)
))
} else {
var c = stack.top()
var cIdent = getIdent(c)
if (c.startsWith("jo")) {
var k = pendingKey.getOrThrow()
pendingKey = None<String>
ret.append(quote(
$(c).put($(k), id)
))
} else if (c.startsWith("ja")) {
ret.append(quote(
$(c).add($(id))
))
} else {
throw Exception("Invalid stack top: " + c)
}
}
return
}
func processArrayValue(t: Token) {
let arrayName = stack.top()
let arrayIdent = getIdent(arrayName)
match (t.kind) {
case TokenKind.RSQUARE =>
partEnd()
tIndex++
case TokenKind.STRING_LITERAL =>
ret.append(quote(
$(arrayName).add(JsonString($(t.value)))
))
state = JsonState.ArrayValue
tIndex++
case TokenKind.INTEGER_LITERAL =>
ret.append(quote(
$(arrayName).add(JsonInt($(t.value)))
))
state = JsonState.ArrayValue
tIndex++
case TokenKind.FLOAT_LITERAL =>
ret.append(quote(
$(arrayName).add(JsonFloat($(t.value)))
))
state = JsonState.ArrayValue
tIndex++
case TokenKind.BOOL_LITERAL =>
ret.append(quote(
$(arrayName).add(JsonBool($(t.value)))
))
state = JsonState.ArrayValue
tIndex++
}
}
while (tIndex < t.size) {
let token = t[tIndex]
match (token.kind) {
case TokenKind.COMMENT | TokenKind.NL =>
tIndex += 1
continue
case _ => ()
}
match (state) {
case JsonState.Initial => match (token.kind) {
case TokenKind.LCURL =>
let name = getObjName()
ret.append(quote(
var $(name) = JsonObject()
))
state = JsonState.ObjectStart
stack.push(name)
tIndex++
case TokenKind.LSQUARE =>
let name = getObjName()
ret.append(quote(
var $(name) = JsonArray()
))
state = JsonState.ArrayStart
stack.push(name)
tIndex++
case TokenKind.STRING_LITERAL =>
ret.append(
quote(
return JsonString($(token.value))
))
state = JsonState.End
tIndex++
case TokenKind.INTEGER_LITERAL =>
ret.append(
quote(
return JsonInt($(token.value))
))
state = JsonState.End
tIndex++
case TokenKind.FLOAT_LITERAL =>
ret.append(
quote(
return JsonFloat($(token.value))
))
state = JsonState.End
tIndex++
case TokenKind.BOOL_LITERAL =>
ret.append(
quote(
return JsonBool($(token.value))
))
state = JsonState.End
tIndex++
case _ =>
let (expr, next) = parseExprFragment(t, startFrom: tIndex)
ret.append(
quote(
return castJsonValue($(expr))
))
state = JsonState.End
tIndex = next
}
case JsonState.ArrayStart =>
}
}
return ret
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment