Friday, December 9, 2016

Log 120916

Right. So, after I removed some small bugs it's time to overhaul the environment data structure I use. For one, I realized I wasn't being very smart about semantic analysis and I knew that the way I represented namespaces (basically a flat list of declarations) would give me back quadratic behavior.

I did some testing on a medium sized file (34k lines,  114k words, 608k characters) containing 6k namespace declarations. Profiling indeed gave me back around 30 seconds of wasted time.
Each sample counts as 0.01 seconds.
  %   cumulative   self                 
 time   seconds   seconds    calls     name    
 39.96      5.95     5.95     6000     RewriteIdentify::rewrite_decl_namespace(...
 24.48      9.60     3.65    42009     std::_Rb_tree...::_M_erase(...
 13.77     11.65     2.05     6001     std::_Rb_tree_node...::_M_copy...
 13.40     13.64     2.00 60883594     std::__shared_ptr..
  4.37     14.29     0.65 63833779     std::_Sp_counted_base...::_M_release()
  2.65     14.69     0.40 62664103     std::vector...::vector...

Which, well, won't do, two orders off. Time to refactor this for performance now, which probably means a bit of a dirty solution. I'll take a day or two for this.

uLisp in 2424 lines of C

The power of Lisp in 2424 readable lines of C code. I am jealous. +10KLoc of C++ now and an incredibility fat binary wasn't what I was aiming at.

Amazing!

Right. I've got rudimentary interactive mode support.

>> "hello world"
""hello world""

Amazing how many small bugs one can code.


>> if System.true then 1 else 2
if System.true then 1 else 2
Segmentation fault (core dumped)

Not to worry. The first is because I haven't completely implemented escape/unescape routines, the second probably because I massage terms in the wrong order in interactive mode.

Log 120916

I really hate it when stuff is conceptually foggy. And I don't see a direct manner of implementing the interactive mode into the interpreter. Something with that I need to redesign the module manager and implement a module which handles interactive mode. Or something...

Nah. That's a bad idea. The module manager handles the loading of modules. And interactive mode isn't a module. Not there.

Wednesday, December 7, 2016

Log 120716

Some more tinkering and the interpreter now can calculate "fib 5"; i.e., it has rudimentary operator support now hacked directly into the language. I need to factor out some of it later again.

My operator support scheme is ridiculously slow. I knew that when I designed it but can't say I am happy about it.

I wanted to benchmark the interpreter but that seems difficult since all trivial benchmarks seem to be gone from here. Moreover, the interpreter lacks basic IO routines. Ah well.

Monday, December 5, 2016

Log 120516

I am tinkering along to get operator support into the language. I once decided that the syntax to code generation part and the VM should be logically separate modules. That now leads to the slightly puzzling situation that I need to inform both parts of predefined operators separately, which isn't very satisfying.

Moreover, I today realized that a simple scheme I wanted to support, just toss in an async combinator through an external library, won't work. That doesn't imply that there isn't another trivial solution but it probably won't be as pretty as, for example, Javascript does it. Ah well.

Ah. I looked that up. Ascync/await will probably work. A bit error prone but, ah well, I am on the edge with an untyped language anyway.

Saturday, December 3, 2016

Log 120316

A lot of times writing code is just tinkering along until you find some solution which fits. Well, for me it is. With inheritance and a macro I got primitive combinator definitions down to some reasonable readable size.

Below, a definition of a dyadic combinator.

class Min: public Dyadic {
public:
    DYADIC_PREAMBLE(Min, "System", "min");

    VMObjectPtr apply(const VMObjectPtr& arg0, 
               const VMObjectPtr& arg1) const override {
        if ( (arg0->tag() == VM_OBJECT_INTEGER) &&
             (arg1->tag() == VM_OBJECT_INTEGER) ) {
            auto i0 = VM_OBJECT_INTEGER_VALUE(arg0);
            auto i1 = VM_OBJECT_INTEGER_VALUE(arg1);
            return VMObjectInteger(i0-i1).clone();
        } else if ( (arg0->tag() == VM_OBJECT_FLOAT) &&
             (arg1->tag() == VM_OBJECT_FLOAT) ) {
            auto f0 = VM_OBJECT_FLOAT_VALUE(arg0);
            auto f1 = VM_OBJECT_FLOAT_VALUE(arg1);
            return VMObjectFloat(f0-f1).clone();
        } else {
            return nullptr;
        }
    }
};

I can't say I am happy about the size of the binary it produces though. I guess it's necessary, but well, it won't run on a PIC.