Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add initial protocol syntax. #26

Draft
wants to merge 28 commits into
base: master
Choose a base branch
from
Draft

Add initial protocol syntax. #26

wants to merge 28 commits into from

Conversation

sigilante
Copy link
Contributor

@sigilante sigilante commented Jan 14, 2025

Target initial syntax:

protocol Arithmetic {
  func add(#) -> #;
  func sub(#) -> #;
};

object Point: Arithmetic {
  let p:(x:@ y:@);
  func init(q:(x:@ y:@)) -> Point {
    p.x = q.x;
    p.y = q.y;
  }
  func add(q:Point) -> Point {
    Point(((p.x + q.x) (p.y + q.y)))
  };
  func sub(q:Point) -> Point {
    Point(((p.x - q.x) (p.y - q.y)))
  };
};

let origin:Point = (0 0);
let vector:Point = (1 2);

origin.add(vector)

Later on, I want to expand protocol syntax and have notes for that, but first let's get it working.

@sigilante sigilante mentioned this pull request Jan 14, 2025
15 tasks
@sigilante
Copy link
Contributor Author

protocl is secondary now to class, which is now the primary focus of this PR.

compose
  class Point(x:@ y:@) {
    init(q:(x:@ y:@)) -> Point {
      x = q.x;
      y = q.y;
    }
    add(q:Point) -> Point {
      Point((x + q.x) (y + q.y));
    }
  };

let origin:Point = Point(0 0);
let vector = Point(1 2);

origin.add(vector)

@sigilante
Copy link
Contributor Author

class Point(x:@ y:@) {
  init(q:(x:@ y:@)) -> Point {
    x.Point = x.q;
    y.Point = y.q;
    (x.Point y.Point)
  }
  add(q:Point) -> Point {
    (x.q y.q)
  }
}

OK, here's a detailed +get-limb pattern for the above:

  1. Attempt to resolve x.q in q:Point with a payload including [p=[%atom p=%number q=%.n] name='y']] name='Point'].
[p=[%core p=[%.y p=[inp=[~ [p=[%limb p=~[[%name p='Point']]] name='q']] out=[p=[%none p=~] name='Point']]] q=[~ [p=[%core p=[%.n p=[n=[p=%add q=[p=[%none p=~] name='']] l=[n=[p=%init q=[p=[%none p=~] name='']] l={} r={}] r=~]] q=[~ [[p=[p=[%atom p=%number q=%.n] name='x'] q=[p=[%atom p=%number q=%.n] name='y']] name='Point']]] name='']]] name='']
  1. q is located in the argument as Point.

  2. x is not located in Point from the argument.

Right now it crashes here. What it needs to do is either continue the search in the payload or replace in the payload to the argument.

The former alters the behavior of +get-limb. It shouldn't break anything that doesn't already work.

The latter edits the AST either at parse time or (more likely) at mint time.

@sigilante
Copy link
Contributor Author

This is a summary of the current situation:

A class is declared

class Point(x:@ y:@) {
  init(q:(x:@ y:@)) -> Point {
    x.Point = x.q;
    y.Point = y.q;
    (x.Point y.Point)
  }
  add(q:Point) -> Point {
    (x.q y.q)
  }
}

which is converted into the AST

[%class
 name=[[p=[p=[%atom p=%number q=%.n] name='x'] q=[p=[%atom p=%number q=%.n] name='y']] name='Point']
 arms=[n=[p=%add
          q=[%func
             type=[p=[%core
                      p=[%.y p=[inp=[~ [p=[%limb p=~[[%name p='Point']]]
                                        name='q']]
                                out=[p=[%none p=~]
                                     name='Point']]]
                      q=~]
                   name='add']
             body=[%lambda
                   p=[arg=[inp=[~ [p=[%limb p=~[[%name p='Point']]] name='q']]
                           out=[p=[%none p=~] name='Point']]
                      body=[p=[%limb p=~[[%name p='q'] [%name p='x']]]
                            q=[%limb p=~[[%name p='q'] [%name p='y']]]]
                      payload=~]]
             next=[%crash ~]]]
       l=[n=[p=%init
             q=[%func
                type=[p=[%core p=[%.y p=[inp=[~ [[p=[p=[%atom p=%number q=%.n]
                                                     name='x']
                                                  q=[p=[%atom p=%number q=%.n]
                                                     name='y']]
                                                 name='q']]
                                         out=[p=[%none p=~]
                                              name='Point']]] q=~]
                      name='init']
                body=[%lambda p=[arg=[inp=[~ [[p=[p=[%atom p=%number q=%.n]
                                                  name='x']
                                               q=[p=[%atom p=%number q=%.n]
                                                  name='y']]
                                              name='q']] out=[p=[%none p=~]
                                                              name='Point']]
                                      body=[%edit
                                            limb=~[[%name p='Point'] [%name p='x']]
                                            val=[%limb p=~[[%name p='q'] [%name p='x']]]
                                            next=[%edit
                                                  limb=~[[%name p='Point'] [%name p='y']]
                                                  val=[%limb p=~[[%name p='q'] [%name p='y']]]
                                                  next=[p=[%limb p=~[[%name p='Point'] [%name p='x']]]
                                                        q=[%limb p=~[[%name p='Point'] [%name p='y']]]]]]
                                      payload=~]]
                next=[%crash ~]]] l={} r={}] r=~]]

The intent is to +mint the class into a double-sample door with arms. The state of the door is supplied using init. The actual values of the state will be supplied to the door by the caller when it is invoked (like %~ now) and the arm will receive its own state at invocation as well. (So there is effectively a two-sample situation to be produced; it's still Nock 9.)

Resolving Point is more complicated that simply an alternative resolution path, because the type can be used in other ways. For instance, what if a method returns List(Point(@ @))?

Some possible points of attack on this problem:

  1. [%limb p=~[[%name p='Point']]] in inp.arg (stub in type details)
  2. [p=[%none p=~] name='Point'] in out.arg (stub in type details, maybe +unify)
  3. If +get-limb bottoms out its jype as a type, then resolve that type in payload (requires changing tracking top-level payload at entry point).
  4. Jype somehow gets resolved before +get-limb.
  5. Alternate to +get-limb (how would you know when to invoke? only for type? but then you've lost the payload)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants