2020년 1월 18일 토요일

Crafting Interpreters - 13. Inheritance 를 읽고

http://craftinginterpreters.com/inheritance.html

- Superclass and Subclass
기존의 class에 상속을 위한 super class 관계 더하기
method를 찾을 때 현재 class에 없으면 super class에서 찾는다.

- super keyword
superclass에 있는 함수를 사용하려면? super.method()로 호출한다. 이 경우 어떤 superclass의 함수를 사용해야 할까? => super.method()를 실제로 부르는 함수의 superclass를 호출해야 한다.
이전에 어떤 environment에서의 값을 사용해야 하는지를 알기 위해 사용했던 방법이 무었이었지? superclass를 찾는 경우에도 마찬가지로 Resolver를 통해 필요한 위치를 기억해 놓도록 한 후, 나중에 함수가 실행 될 때 environment에 이 super를 넣어준다.

Crafting Interpreters - 12. Classes 를 읽고

 http://craftinginterpreters.com/classes.html

기존에 되어 있는 것에서 class를 추가만 하면 된다.
가장 먼저 class 선언 부분을 LoxClass를 통해 추가하고 instance를 생성하는 부분은 LoxInstance를 통해 생성한다.

- Instance의 property 찾기(get)
someObject.someProperty의 형태이므로 someObject를 찾고 여기의 someProperty를 찾는다.

- Instance의 property에 값 설정(set)
someObject.someProperty = value 의 형태이므로 위 get에서 한대로 someObject의 someProperty를 찾고 여기에 value를 설정한다.

- Instance에서 method 찾기
LoxClass에 method들을 저장해 놓고, LoxInstance에서 someObject.some 으로 찾을 때 get 함수에서 먼저 property가 있는지 확인해보고 없으면 method가 있는지 확인해 본다.
property는 LoxInstance에 저장되어 있고 method는 LoxClass에 저장되어 있다.

- This
Resolver에서 this를 찾을 위치를 저장해 놓는다.
LoxInstance에서 method를 찾아서 실행할 때 environment에 this도 있어야 하므로 새로운 LoxFunction을 만들면서 여기에 this를 포함하고 있는 environment를 넘겨준다.

- Constructor
init 함수를 constructor로 사용하자. Class에 선언된 함수중 init 함수가 있으면 이를 constructor로 사용한다. init 함수의 경우에는 return이 this가 되도록 한다.


2020년 1월 11일 토요일

Crafting Interpreters - 11. Resolving and Binding 을 읽고

http://craftinginterpreters.com/resolving-and-binding.html

지금까지의 내용을 가지고 다음의 코드가 어떤 결과를 표시할 지 생각해보자.

var a = "global";
{
  fun showA() {
    print a;
  }

  showA();
  var a = "block";
  showA();
}

결과는 다음과 같다.

global
block

뭐가 문제일까?

앞장에서 함수에 Environment를 적용할 때 함수가 실행될 때마다 Environment를 새로 생성했다. 그리고, 함수안에서 사용하는 변수의 값을 찾을 때 현재 Environment로부터 부모 Environment로 점차로 찾아가는 형태로 구현을 했다.

여기의 어떤 점이 문제였을까?

위의 코드에서 showA()를 선언했을 때의 Environment를 살펴보자.

global environment(a="global") <- block environment() <- showA environment()

따라서, 처음 showA(); 를 호출할 때는 global environment의 a가 찾아진다. 그런데 두번째 a인 var a = "block"; 가 실행되면서 block environment에 a="block" 가 추가된다. 이 다음에 showA() 를 호출하면 앞에서처럼 점진적으로 Environment를 찾아갈 텐데 block environment에 a가 추가되었기 때문에 여기의 a를 찾게 되고 이 a 의 값이 출력되게 된다.

위의 문제를 해결하려면?
아래와 같은 코드가 있을 때 1과 2에서의 scope가 실제로는 같지 않아야 함을 의미한다.
{
  var a;
  // 1.
  var b;
  // 2.
}

그렇다면, 이 문제를 어떻게 해결할 수 있을까?

첫번째로는 변수 선언이나 함수 선언의 경우마다 새로운 scope를 생성하는 것이다.(이전에는 기존의 Environment에 새로운 선언을 바로 추가했다.)

두번째로는 Semantic Analysis를 사용하는 것이다.

이 방법은 block과 function의 경우 새로운 scope를 생성하고, variable이나 assignment가 있는 경우 어떤 scope에 있는 값이 사용되어야 하는지를 미리 설정해 놓고 나중에 이 값을 사용한다.

우리는 두번째 방법으로 구현을 변경해 볼 것이다.
-> parser를 통해 나온 결과를 바로 interpreter에 보내지 않고 이 사이에 Resolver를 통해 Semantic Analysis를 한 후 interpreter에서 변수를 사용할 때 이 정보를 사용한다.

2020년 1월 8일 수요일

Crafting Interpreters - 10. Functions 를 읽고

http://craftinginterpreters.com/functions.html

함수에서의 return을 위해 exception을 사용한다.
함수 시작시 Environment를 새로 할당하여 시작한다.
함수가 선언되는 시점의 Environment를 저장하고 있다가 함수 시작시 새로 할당되는 Environment의 parent로 설정해준다.


Crafting Interpreters - 9. Control Flow 를 읽고

http://craftinginterpreters.com/control-flow.html

Turing Machines

if, logical operator(and와 or), while, for 를 추가



for 문 같은 경우 while 문으로 쉽게 변경이 가능하다. 따라서, 내부적으로는 for 를 while 로 변환해서 사용할 수 있다. 이러한 것을 syntactic sugar 라고 한다.




Building asynchronous views in SwiftUI 정리

Handling loading states within SwiftUI views self loading views View model 사용하기 Combine을 사용한 AnyPublisher Making SwiftUI views refreshable r...