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에서 변수를 사용할 때 이 정보를 사용한다.

댓글 없음:

댓글 쓰기

Building asynchronous views in SwiftUI 정리

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