All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sfj.exemplars.JsonPegParser Maven / Gradle / Ivy

Go to download

This is a collection of disparate pieces of code, each file containing a single piece of functionality. The idea is software minimalism, you get 1000 lines of Java code, no dependencies. Collection of useful things, especially for prototyping/rapid development.

There is a newer version: 1.2.0
Show newest version
/*
 * Copyright 2020 C. Schanck
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.sfj.exemplars;

import org.sfj.JSONOne;
import org.sfj.PegLegParser;

import java.text.NumberFormat;
import java.text.ParseException;

/**
 * JSON parser, leaves a single object on top of the stack, using
 * the JSONOne package.
 */
public class JsonPegParser extends PegLegParser {
  public PegLegRule json() {
    return named("json", seqOf(firstOf(jsonObject(), jsonArray())));
  }

  PegLegRule jsonObject() {
    Ref map = new Ref<>(JSONOne.JMap::new);
    return named("jsonObject",
      () -> seqOf(ws('{'), optOf(seqOf(pair(), ex(addPair(map)), zeroPlusOf(',', pair(), ex(addPair(map))), optOf(ws(',')))),
        ws('}'), ex(() -> values().push(map.get()))).refs(map).rule());
  }

  private Runnable addPair(Ref map) {
    return () -> {
      JSONOne.JObject val = values().pop();
      JSONOne.JString key = (JSONOne.JString) values().pop();
      map.get().put(key.stringValue(), val);
    };
  }

  PegLegRule pair() {
    return named("pair", seqOf(jsonString(), ws(':'), value()));
  }

  PegLegRule value() {
    return named("value", firstOf(jsonString(), // pushed below
      seqOf(jsonNumber(), ex(this::matchAsNumber)), jsonObject(), // pushed below
      jsonArray(), // pushed below
      seqOf(ws("true"), ex(() -> values().push(new JSONOne.JBoolean(true)))),
      seqOf(ws("false"), ex(() -> values().push(new JSONOne.JBoolean(false)))),
      seqOf(ws("null"), ex(() -> values().push(new JSONOne.JNull())))));
  }

  private void matchAsNumber() {
    try {
      Number num = NumberFormat.getInstance().parse(get().match().get());
      values().push(new JSONOne.JNumber(num));
    } catch (ParseException e) {
      error(e.getMessage());
    }
  }

  PegLegRule jsonString() {
    return named("jsonString", seqOf(ws(), "\"", zeroPlusOf(chars()),
      ex(() -> values().push(new JSONOne.JString(JSONOne.unescapeString(get().match().orElse(""))))), "\"", ws()));
  }

  PegLegRule jsonNumber() {
    return named("jsonNumber", seqOf(integer(), optOf(frac(), optOf(exp())), ws()));
  }

  public PegLegRule jsonArray() {
    Ref arr = new Ref<>(JSONOne.JArray::new);
    return named("jsonArray", () -> seqOf(ws('['),
      optOf(value(), ex(() -> arr.get().add(values().pop())), zeroPlusOf(ws(','), value(), ex(() -> arr.get().add(values().pop()))),
        optOf(ws(','))), ws(']'), ex(() -> values().push(arr.get()))).refs(arr).rule());
  }

  PegLegRule chars() {
    return firstOf(escapedChar(), normalChar());
  }

  PegLegRule escapedChar() {
    return seqOf("\\", firstOf(anyOf("\"\\/fnrt"), unicode()));
  }

  PegLegRule normalChar() {
    return noneOf("\"\\");
  }

  PegLegRule unicode() {
    return seqOf("u", hex(), hex(), hex(), hex());
  }

  PegLegRule integer() {
    return seqOf(optOf(anyOf("+-")), firstOf('0', seqOf(charRange('1', '9'), zeroPlusOf(digit()))));
  }

  PegLegRule digits() {
    return onePlusOf(digit());
  }

  PegLegRule digit() {
    return charRange('0', '9');
  }

  PegLegRule hex() {
    return firstOf(charRange('0', '9'), charRange('a', 'f').ignoreCase());
  }

  PegLegRule frac() {
    return seqOf('.', digits());
  }

  PegLegRule exp() {
    return seqOf(ch('e').ignoreCase(), optOf(anyOf("+-")), digits());
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy