ling言語

//
//  ling.cpp
//  Ling
//
//  Created by marycore.jp on 2020/12/24.
//  Copyright (C) 2019 marycore.jp. All rights reserved.
//

#include <assert.h>

namespace ln {
  struct Cell;
  
  struct Obj {
    unsigned _ref = 0;
    
    Obj* retain() { return ++_ref, this; }
    Obj* release() {
      if (0 != --_ref) return this;
      return delete this, nullptr;
    }
    
    virtual ~Obj() {}
    virtual operator int() { return 0; }
    virtual Obj* eval(Cell* args) { return this->retain(); }
    
    template<class Node> static Obj* parse(const char** p);
    static Obj* parse(const char* s) { return parse<Cell>(&s); }
  };
  
  struct Nil : Obj {};
  
  struct Cell : Obj {
    Obj *_a, *_b;
    Cell(Obj *a = nullptr, Obj *b = nullptr) : _a(a ? a->retain() : a), _b(b ? b->retain() : b) {}
    virtual ~Cell() { if (_a) _a->release(); if (_b) _b->release(); }
    void push(Obj* v) {
      if (!_a) { _a = v->retain(); return; }
      if (_b) return static_cast<Cell*>(_b)->push(v);
      (_b = new Cell{v, nullptr})->retain();
    }
    virtual Obj* eval(Cell* args) { return _a ? _a->eval(static_cast<Cell*>(_b)) : (new Nil{})->retain(); }
  };
  
  struct Ary : Cell {
    virtual Obj* eval(Cell* args) {
      Cell *r = new Ary{};
      Cell *b = this;
      while (b && b->_a) {
        auto v = b->_a->eval(nullptr);
        r->push(v);
        v->release();
        b = static_cast<Cell*>(b->_b);
      }
      return r->retain();
    }
  };
  
  struct Num : Obj {
    int _v;
    Num(int v) : _v{v} {}
    virtual operator int() { return _v; }
    virtual Obj* eval(Cell* args) { return (new Num{_v})->retain(); }
    static Obj* parse(const char **p) {
      auto isdigit = [](auto c) { return '0' <= c && '9' >= c; };
      if (!isdigit(**p)) return nullptr;
      auto v = new Num{**p - '0'};
      while (isdigit(*(*p + 1))) v->_v = v->_v * 10 + (*++*p - '0');
      return v;
    }
  };
  
  template<class T = void, char C = ' '> struct Calc : Obj {
    static Obj* parse(const char** p);
    virtual Obj* eval(Cell* args);
  };
  struct Add : Calc<Add, '+'> {
    Obj* binary(Obj* a, Obj* b) { return new Num{int(*a) + int(*b)}; }
    Obj* unary(Obj* a) { if (auto v = dynamic_cast<Cell*>(a)) return v->_b ? static_cast<Obj*>(v->_b) : new Nil{}; return a; } };
  struct Sub : Calc<Sub, '-'> {
    Obj* binary(Obj* a, Obj* b) { return new Num{int(*a) - int(*b)}; }
    Obj* unary(Obj* a) { return new Num{-int(*a)}; } };
  struct Mul : Calc<Mul, '*'> {
    Obj* binary(Obj* a, Obj* b) { return new Num{int(*a) * int(*b)}; }
    Obj* unary(Obj* a) { if (auto v = dynamic_cast<Cell*>(a)) { return v->_a ? v->_a : new Nil{}; } return a; } };
  struct Div : Calc<Div, '/'> {
    Obj* binary(Obj* a, Obj* b) { return new Num{int(*a) / int(*b)}; }
    Obj* unary(Obj* a) { return a; } };
  template<class T, char C> Obj* Calc<T, C>::parse(const char** p) {
    if ('+' == **p) { auto x = new Add{}; return x; }
    if ('-' == **p) { auto x = new Sub{}; return x; }
    if ('*' == **p) { auto x = new Mul{}; return x; }
    if ('/' == **p) { auto x = new Div{}; return x; } return nullptr;
  }
  template<class T, char C> Obj* Calc<T, C>::eval(Cell* args) {
    if (!args) return this->retain();
    auto a = args->_a;
    auto b = static_cast<Cell*>(args->_b);
    if (!b) {
      auto t = a->eval(nullptr);
      auto r = static_cast<T*>(this)->unary(t)->retain();
      t->release();
      return r;
    }
    auto r = a;
    do {
      auto x = r->eval(nullptr);
      auto y = b->_a->eval(nullptr);
      if (r != a) r->release();
      r = static_cast<T*>(this)->binary(x, y)->retain();
      x->release();
      y->release();
      b = static_cast<Cell*>(b->_b);
    } while (nullptr != b);
    return r;
  }
  
  template<class Node> Obj* Obj::parse(const char **p) {
    auto a = new Node{};
    do {
      if (' ' == **p) continue;
      if ('(' == **p) { a->push(Obj::parse<Cell>(&++*p)); continue; }
      if ('[' == **p) { a->push(Obj::parse<Ary >(&++*p)); continue; }
      if (')' == **p) break;
      if (']' == **p) break;
      if (auto v =    Num::parse(p)) { a->push(v); continue; }
      if (auto v = Calc<>::parse(p)) { a->push(v); continue; }
    } while (*++*p);
    return a;
  }
  
  int ling(const char* s) {
    auto t = Obj::parse(s)->retain();
    auto r = t->eval(nullptr);
    int i = static_cast<int>(*r);
    r->release();
    t->release();
    return i;
  }
}

int main() {
  assert(  2 == ln::ling("2") );
  assert( -2 == ln::ling("- 2") );
  assert(  3 == ln::ling("+ 1 2") );
  assert(  6 == ln::ling("+ 1 2 3") );
  assert( -3 == ln::ling("- (+ 1 2)") );
  assert(  2 == ln::ling("+ 1 2 (- 1)") );
  assert(  6 == ln::ling("* (- 2) (- 3)") );
  assert( -3 == ln::ling("- (* (+ [2 3]))") );
}